IllegalStateException,指定的孩子已经有一个父母 - ListFragment

Posted

技术标签:

【中文标题】IllegalStateException,指定的孩子已经有一个父母 - ListFragment【英文标题】:IllegalStateException, the specified child already has a parent - ListFragment 【发布时间】:2015-02-24 18:36:41 【问题描述】:

我已经查看了这里的所有此类错误,但没有任何解决方法。我正在尝试以编程方式向我的活动添加一个片段(在其他代码的帮助下),我运行它并收到此错误:

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

我有一个活动只是托管一个片段,在其xml 中使用FrameLayout,然后我在该活动中编码FragmentManager 以启动它。我的片段视图的详细信息在我的片段类ContactsFragment.javaonCreateView() 中。在这里,我分配了一个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_
    android:layout_
    tools:context="org.azurespot.practiceapp.addressbook.AddressBook" >

     <FrameLayout
         android:id="@+id/contacts_fragment"
         android:layout_
         android:layout_ >
     </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://***.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_
    android:layout_ >

    <ListView
        android:id="@android:id/list"
        android:layout_
        android:layout_
        android:layout_weight="1" >
    </ListView>

    <TextView 
        android:id="@id/android:empty"
        android:layout_
        android:layout_
        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_
    android:layout_ >

    <ImageView 
        android:id="@+id/contact_thumbnail"
        android:layout_
        android:layout_ />

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

    </TextView>

    <TextView
        android:id="@+id/contact_number"
        android:layout_
        android:layout_
        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 ComponentInfocom.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 更多

【问题讨论】:

【参考方案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_
    android:background="#FF0000"
    android:layout_ >

    <ListView
        android:id="@android:id/list"
        android:layout_
        android:layout_
        android:layout_weight="1" >
    </ListView>

    <TextView 
        android:id="@id/android:empty"
        android:layout_
        android:layout_
        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_
    android:layout_
    tools:context="org.azurespot.practiceapp.addressbook.AddressBook" >

     <FrameLayout
         android:id="@+id/contacts_fragment"
         android:layout_
         android:layout_ >
     </FrameLayout>

</LinearLayout>

【讨论】:

感谢 droidkid,但我需要自定义布局,因为我想从列表中提取照片缩略图、姓名和电话号码。 listViewrootView 基本相同,因为它被分配给rootView.findViewById(android.R.id.list) 方法。但我确实检查过,用rootView 替换它,我仍然得到一个白页。在 ListFragment 文档中,我得到了 onCreateView() 的说明,除非其中有其他问题。 我做的一件事就是将它添加到我的AddressBook 活动中:FragmentManager fm = getFragmentManager(); if (fm.findFragmentById(R.id.contacts_fragment) == null)fm.beginTransaction().add(R.id.contacts_fragment, new ContactsFragment()); 并且错误消失了,但我的列表仍然是空白的,这告诉我 ListView 不是 @987654333 @。我不知道为什么它不是null,但仍然没有显示任何内容。 :( 好的,很高兴它成功了。您的 prblm 在 onCreateView() 方法中,在那里您创建了另一个 ContactsFragment 实例并将适配器值设置为该方法。这也是在附加片段布局之前完成的。如果您有解决方案,请接受答案 您的旧 FragmentTranscation 代码是正确的。检查 嘿,你是对的,我这样做的顺序肯定与我想象的不同。嗯,非常感谢。你的回答真的是救命稻草。 :)

以上是关于IllegalStateException,指定的孩子已经有一个父母 - ListFragment的主要内容,如果未能解决你的问题,请参考以下文章

Recyclerview 中的对话框 - IllegalStateException:指定的孩子已经有一个父母

MvcTest出错java.lang.IllegalStateException:Failed to load ApplicationContext

访问tomcat出现HTTP Status 500 - java.lang.IllegalStateException: No output folder

java.lang.IllegalStateException: Can not perform this action after onSaveInstanceState

java.lang.IllegalStateException: Method get not annotated with HTTP method type (ex. GET, POST);(代码片

IllegalStateException:链接没有设置 NavController