IllegalStateException,指定的子节点已经有一个父级 - ListFragment

时间:2014-12-28 06:39:07

标签: android android-fragments android-listview android-listfragment

我已经看过这里的每一个错误,但没有任何修复它。我试图以编程方式将一个片段添加到我的活动中(在其他代码的帮助下)并运行它并得到此错误:

IllegalStateException, the specified child already has a parent, you must call removeView() on the child's parent first.

我有一个活动只是托管一个片段,在FrameLayout中使用xml,然后我在该活动中编码FragmentManager以启动它。我的片段视图的详细信息位于我的片段类onCreateView()中,ContactsFragment.java。在这里,我指定了一个ListView作为我的片段,我希望在我的AddressBook.java活动中查看。

感谢您的帮助,如果您能发现我的代码中的任何错误。下面是Activity,fragment,xmls和logcat。

编辑:当我取出FragmentManager代码时,错误就消失了,但随后我得到一个空白的白色活动。这有助于任何人了解错误的本质吗?感谢。

代码注释掉了:

        // Begin the transaction
        FragmentTransaction ft = getFragmentManager().beginTransaction();
        // Replace the container with the new fragment
        ft.add(R.id.contacts_fragment, new ContactsFragment());
        // Execute the changes specified
        ft.commit();

AddressBook.java

package org.azurespot.practiceapp.addressbook;

import android.app.Activity;
import android.app.FragmentTransaction;
import android.os.Bundle;

import com.example.practiceapp.R;


public class AddressBook extends Activity {

    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_address_book);

        // Begin the transaction
        FragmentTransaction ft = getFragmentManager().beginTransaction();
        // Replace the container with the new fragment
        ft.replace(R.id.contacts_fragment, new ContactsFragment());
        // or ft.add(R.id.your_placeholder, new FooFragment());
        // Execute the changes specified
        ft.commit();
    }

}

activity_address_book.xml

<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    tools:context="org.azurespot.practiceapp.addressbook.AddressBook" >

     <FrameLayout
         android:id="@+id/contacts_fragment"
         android:layout_width="0dp"
         android:layout_height="match_parent" >
     </FrameLayout>

</LinearLayout>

ContactsFragment.java

package org.azurespot.practiceapp.addressbook;

import android.app.ListFragment;
import android.app.LoaderManager.LoaderCallbacks;
import android.content.CursorLoader;
import android.content.Loader;
import android.database.Cursor;
import android.net.Uri;
import android.os.Bundle;
import android.provider.ContactsContract;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.CursorAdapter;
import android.widget.ListView;
import android.widget.SimpleCursorAdapter;

import com.example.practiceapp.R;

/*
 * Partially from http://stackoverflow.com/questions/18199359/how-to-display-contacts-in-a-listview-in-android-for-android-api-11
 */

public class ContactsFragment extends ListFragment implements 
                                LoaderCallbacks<Cursor>{

    private CursorAdapter listAdapter;
    public Cursor cursor;
    private android.content.Context context;
    public View view;
    public static Uri uri;
    public static ListView listView;

    public static final String[] FROM = new String[]{ 
            ContactsContract.Contacts.PHOTO_THUMBNAIL_URI,
            ContactsContract.Contacts.DISPLAY_NAME,
            ContactsContract.Contacts.HAS_PHONE_NUMBER };

    private static final int[] TO = { R.id.contact_thumbnail, 
        R.id.contact_name, R.id.contact_number };

    // columns requested from the database
    private static final String[] PROJECTION = new String[]{
        ContactsContract.Contacts._ID,
            ContactsContract.Contacts.PHOTO_THUMBNAIL_URI,
            ContactsContract.Contacts.DISPLAY_NAME,
            ContactsContract.CommonDataKinds.Phone.NUMBER,
    };

    // this goes in the CursorLoader parameter list, it filters
    // out only those contacts who have a phone number
    private static final String FILTER = 
            ContactsContract.Contacts.HAS_PHONE_NUMBER  + " LIKE ?";

    private static final int URL_LOADER = 0;

    @Override
    public View onCreateView(LayoutInflater inflater,
             ViewGroup container,Bundle bundle) {

        if(listView != null) {
            return listView; 
        }

        // since using ListFragment, you must inflate your view this way
        View rootView = inflater.inflate(R.layout.fragment_list_view,
                container, false);
        listView = (ListView) rootView
                                .findViewById(android.R.id.list);

        // create a new SimpleCursorAdapter adapter
        context = getActivity();
        Cursor c = null; // there is no cursor yet
        int flags = 0; // no auto-re-query! (My loader re-queries.)
        // put List UI row in adapter, create empty adapter
        listAdapter = new SimpleCursorAdapter(context, 
                R.layout.fragment_list_item, c, FROM, TO, flags);

        // Initializes the CursorLoader. The URL_LOADER value is 
        // eventually passed to onCreateLoader().
        getLoaderManager().initLoader(URL_LOADER, null, this);

        // ListFragment then sets the adapter
        ContactsFragment listFrag = new ContactsFragment();
        listFrag.setListAdapter(listAdapter);

        return listView;

    } // end onCreateView 


    // Empty public constructor, required by the system
    public ContactsFragment() {}

    public void onActivityCreated(Bundle savedInstanceState) {
        super.onActivityCreated(savedInstanceState);

    }

    /*
     * The 3 methods below are standard for the LoaderCallbacks<Cursor> interface.
     * Here, CursorLoader does a query in the background.
     */

    @Override
    public Loader<Cursor> onCreateLoader(int id, Bundle args) {
        // load from the "Contacts table"
        Uri contentUri = ContactsContract.CommonDataKinds.Phone.CONTENT_URI;

        // the query
        return new CursorLoader(getActivity(),
                contentUri,
                PROJECTION,
                FILTER,
                null,
                ContactsContract.Contacts.DISPLAY_NAME + " ASC");
    }

    @Override
    public void onLoadFinished(Loader<Cursor> loader, Cursor data) {
         // Once cursor is loaded, give it to adapter
        listAdapter.swapCursor(data);

        // The list should now be shown.
        if (isResumed()) {
            setListShown(true);
        } else {
            setListShownNoAnimation(true);
        }
    }

    @Override
    public void onLoaderReset(Loader<Cursor> loader) {
        // Delete the reference to the existing Cursor,
        // so it can recycle it
        listAdapter.swapCursor(null);

    }

}

fragment_list_view.xml

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="match_parent" >

    <ListView
        android:id="@android:id/list"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:layout_weight="1" >
    </ListView>

    <TextView 
        android:id="@id/android:empty"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:background="#FF0000"
        android:text="No data"/>

</LinearLayout>

fragment_list_item.xml

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="match_parent" >

    <ImageView 
        android:id="@+id/contact_thumbnail"
        android:layout_width="50dp"
        android:layout_height="wrap_content" />

    <TextView
        android:id="@+id/contact_name"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_weight="1"
        android:ems="10" >

    </TextView>

    <TextView
        android:id="@+id/contact_number"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_weight="1"
        android:ems="10" >

    </TextView>

</LinearLayout>

logcat的

12-27 22:37:17.145: I/PersonaManager(12130): getPersonaService() name persona_policy
12-27 22:37:17.165: D/skia(12130): GFXPNG PNG bitmap created width:48 height:48 bitmap id is 270 
12-27 22:37:17.175: E/MoreInfoHPW_ViewGroup(12130): Parent view is not a TextView
12-27 22:37:17.185: D/skia(12130): GFXPNG PNG bitmap created width:72 height:72 bitmap id is 271 
12-27 22:37:17.185: D/skia(12130): GFXPNG PNG bitmap created width:144 height:144 bitmap id is 272 
12-27 22:37:17.205: D/skia(12130): GFXPNG PNG bitmap created width:144 height:144 bitmap id is 273 
12-27 22:37:17.295: I/Adreno-EGL(12130): <qeglDrvAPI_eglInitialize:410>: EGL 1.4 QUALCOMM build:  ()
12-27 22:37:17.295: I/Adreno-EGL(12130): OpenGL ES Shader Compiler Version: E031.24.00.08+13
12-27 22:37:17.295: I/Adreno-EGL(12130): Build Date: 03/20/14 Thu
12-27 22:37:17.295: I/Adreno-EGL(12130): Local Branch: 0320_AU200_patches
12-27 22:37:17.295: I/Adreno-EGL(12130): Remote Branch: 
12-27 22:37:17.295: I/Adreno-EGL(12130): Local Patches: 
12-27 22:37:17.295: I/Adreno-EGL(12130): Reconstruct Branch: 
12-27 22:37:17.325: D/OpenGLRenderer(12130): Enabling debug mode 0
12-27 22:37:18.705: I/PersonaManager(12130): getPersonaService() name persona_policy
12-27 22:37:18.715: E/MoreInfoHPW_ViewGroup(12130): Parent view is not a TextView
12-27 22:37:18.735: D/skia(12130): GFXPNG PNG bitmap created width:12 height:12 bitmap id is 274 
12-27 22:37:18.735: D/AbsListView(12130): Get MotionRecognitionManager
12-27 22:37:18.745: D/AndroidRuntime(12130): Shutting down VM
12-27 22:37:18.745: W/dalvikvm(12130): threadid=1: thread exiting with uncaught exception (group=0x41737da0)
12-27 22:37:18.745: E/AndroidRuntime(12130): FATAL EXCEPTION: main
12-27 22:37:18.745: E/AndroidRuntime(12130): Process: com.example.practiceapp, PID: 12130
12-27 22:37:18.745: E/AndroidRuntime(12130): java.lang.RuntimeException: Unable to start activity ComponentInfo{com.example.practiceapp/org.azurespot.practiceapp.addressbook.AddressBook}: java.lang.IllegalStateException: The specified child already has a parent. You must call removeView() on the child's parent first.
12-27 22:37:18.745: E/AndroidRuntime(12130):    at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:2395)
12-27 22:37:18.745: E/AndroidRuntime(12130):    at android.app.ActivityThread.handleLaunchActivity(ActivityThread.java:2453)
12-27 22:37:18.745: E/AndroidRuntime(12130):    at android.app.ActivityThread.access$900(ActivityThread.java:173)
12-27 22:37:18.745: E/AndroidRuntime(12130):    at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1303)
12-27 22:37:18.745: E/AndroidRuntime(12130):    at android.os.Handler.dispatchMessage(Handler.java:102)
12-27 22:37:18.745: E/AndroidRuntime(12130):    at android.os.Looper.loop(Looper.java:136)
12-27 22:37:18.745: E/AndroidRuntime(12130):    at android.app.ActivityThread.main(ActivityThread.java:5579)
12-27 22:37:18.745: E/AndroidRuntime(12130):    at java.lang.reflect.Method.invokeNative(Native Method)
12-27 22:37:18.745: E/AndroidRuntime(12130):    at java.lang.reflect.Method.invoke(Method.java:515)
12-27 22:37:18.745: E/AndroidRuntime(12130):    at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:1268)
12-27 22:37:18.745: E/AndroidRuntime(12130):    at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:1084)
12-27 22:37:18.745: E/AndroidRuntime(12130):    at dalvik.system.NativeStart.main(Native Method)
12-27 22:37:18.745: E/AndroidRuntime(12130): Caused by: java.lang.IllegalStateException: The specified child already has a parent. You must call removeView() on the child's parent first.
12-27 22:37:18.745: E/AndroidRuntime(12130):    at android.view.ViewGroup.addViewInner(ViewGroup.java:3771)
12-27 22:37:18.745: E/AndroidRuntime(12130):    at android.view.ViewGroup.addView(ViewGroup.java:3624)
12-27 22:37:18.745: E/AndroidRuntime(12130):    at android.view.ViewGroup.addView(ViewGroup.java:3569)
12-27 22:37:18.745: E/AndroidRuntime(12130):    at android.view.ViewGroup.addView(ViewGroup.java:3545)
12-27 22:37:18.745: E/AndroidRuntime(12130):    at android.app.FragmentManagerImpl.moveToState(FragmentManager.java:901)
12-27 22:37:18.745: E/AndroidRuntime(12130):    at android.app.FragmentManagerImpl.moveToState(FragmentManager.java:1062)
12-27 22:37:18.745: E/AndroidRuntime(12130):    at android.app.BackStackRecord.run(BackStackRecord.java:684)
12-27 22:37:18.745: E/AndroidRuntime(12130):    at android.app.FragmentManagerImpl.execPendingActions(FragmentManager.java:1453)
12-27 22:37:18.745: E/AndroidRuntime(12130):    at android.app.Activity.performStart(Activity.java:5460)
12-27 22:37:18.745: E/AndroidRuntime(12130):    at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:2368)
12-27

22:37:18.745:E / AndroidRuntime(12130):... 11 more

1 个答案:

答案 0 :(得分:1)

在“ContactsFragment.java”类中,您没有返回膨胀的视图。而是返回列表视图。尝试更改以下代码

@Override
public View onCreateView(LayoutInflater inflater,
             ViewGroup container,Bundle bundle) {

       // since using ListFragment, you must inflate your view this way
        View rootView = inflater.inflate(R.layout.fragment_list_view,
                container, false);

        return rootView;
}

@Override
public void onActivityCreated(Bundle savedInstanceState) {
       super.onActivityCreated(savedInstanceState);
         listView = (ListView)getListView();

        // create a new SimpleCursorAdapter adapter
        context = getActivity();
        Cursor c = null; // there is no cursor yet
        int flags = 0; // no auto-re-query! (My loader re-queries.)
        // put List UI row in adapter, create empty adapter
        listAdapter = new SimpleCursorAdapter(context, 
                R.layout.fragment_list_item, c, FROM, TO, flags);

        // Initializes the CursorLoader. The URL_LOADER value is 
        // eventually passed to onCreateLoader().
        getLoaderManager().initLoader(URL_LOADER, null, this);

        setListAdapter(listAdapter);

}

使用相同的replace()方法是Activity

       // Begin the transaction
        FragmentTransaction ft = getFragmentManager().beginTransaction();
        // Replace the container with the new fragment
        ft.replace(R.id.contacts_fragment, new ContactsFragment());
        // or ft.add(R.id.your_placeholder, new FooFragment());
        // Execute the changes specified
        ft.commit();

fragment_list_view.xml

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:background="#FF0000"
    android:layout_height="match_parent" >

    <ListView
        android:id="@android:id/list"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:layout_weight="1" >
    </ListView>

    <TextView 
        android:id="@id/android:empty"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:background="#FF0000"
        android:text="No data"/>

</LinearLayout>

activity_address_book.xml

<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    tools:context="org.azurespot.practiceapp.addressbook.AddressBook" >

     <FrameLayout
         android:id="@+id/contacts_fragment"
         android:layout_width="match_parent"
         android:layout_height="match_parent" >
     </FrameLayout>

</LinearLayout>