如何解决viewpager:指定的子节点已经有父节点。 您必须首先在孩子的父母上调用removeView()

在我的项目中,我使用的是viewpager,其中包含三个名为HistoryMainMap选项卡。 主要活动包括计时器,秒表等。 地图显示谷歌地图。 现在进入历史我只使用简单的Textview。

Viewpager流向: 历史主要地图

我将Main设置为当前项目(Bydefault Main tag display)。现在我从Main > Map and Map > Main滑动它的工作完美。 但是当从Main > History中滑动时没有错误但是从History返回MainHistory > Main )eclipse给出了如下错误:

 E/AndroidRuntime( 533): java.lang.IllegalStateException: The specified child already has a parent. You must call removeView() on the child's parent first. 

我正在使用intent into Map Activity 。请检查下面的代码。请让我知道如何解决我的问题。

ViewPager类:

 @Override public Fragment getItem(int position) { // return SwipeyTabFragment.newInstance(TITLES[position]); Fragment f = new Fragment(); switch (position) { case 0: f = History.newInstance(position); break; case 1: f = Main.newInstance(position); break; case 2: f = Map.newInstance(position); break; } return f; } 

历史课:

 public class History extends Fragment { public static Fragment newInstance(int position) { History f = new History(); Bundle args = new Bundle(); args.putInt("title", position); f.setArguments(args); return f; } @Override public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) { ViewGroup root = (ViewGroup) inflater.inflate(R.layout.history, null); ( (TextView) root.findViewById(R.id.text)).setText("Hello"); return root; } } 

Main.class:

  public class Main extends Fragment implements GPSCallback { ...... public static Fragment newInstance(int position) { Main f = new Main(); Bundle args = new Bundle(); args.putInt("title", position); f.setArguments(args); return f; } @Override public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) { final ViewGroup root = (ViewGroup) inflater .inflate(R.layout.main, null); ....... return root; } ........ } 

Map.class:

 public class Map extends Fragment { private static final String KEY_STATE_BUNDLE = "localActivityManagerState"; private LocalActivityManager mLocalActivityManager; protected LocalActivityManager getLocalActivityManager() { return mLocalActivityManager; } @Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); Bundle state = null; if (savedInstanceState != null) { state = savedInstanceState.getBundle(KEY_STATE_BUNDLE); } mLocalActivityManager = new LocalActivityManager(getActivity(), true); mLocalActivityManager.dispatchCreate(state); } public static Fragment newInstance(int position) { Map f = new Map(); Bundle args = new Bundle(); args.putInt("title", position); f.setArguments(args); return f; } @Override public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) { Intent i = new Intent(getActivity(), MapViewActivity.class); // Intent i = new Intent(getActivity(), hellogooglemap.class); Window w = mLocalActivityManager.startActivity("tag", i); View currentView=w.getDecorView(); currentView.setVisibility(View.VISIBLE); currentView.setFocusableInTouchMode(true); ((ViewGroup) currentView).setDescendantFocusability(ViewGroup.FOCUS_AFTER_DESCENDANTS); return currentView; /*ViewGroup root = (ViewGroup) inflater.inflate(R.layout.history, null); ( (TextView) root.findViewById(R.id.text)).setText("Hello"); return root;*/ } @Override public void onSaveInstanceState(Bundle outState) { super.onSaveInstanceState(outState); outState.putBundle(KEY_STATE_BUNDLE, mLocalActivityManager.saveInstanceState()); } @Override public void onResume() { super.onResume(); mLocalActivityManager.dispatchResume(); } @Override public void onPause() { super.onPause(); mLocalActivityManager.dispatchPause(getActivity().isFinishing()); } @Override public void onStop() { super.onStop(); mLocalActivityManager.dispatchStop(); } @Override public void onDestroy() { super.onDestroy(); mLocalActivityManager.dispatchDestroy(getActivity().isFinishing()); } } 

Logcat:

  E/AndroidRuntime( 533): java.lang.IllegalStateException: The specified child already has a parent. You must call removeView() on the child's parent first. E/AndroidRuntime( 533): at android.view.ViewGroup.addViewInner(ViewGroup.java:1976) E/AndroidRuntime( 533): at android.view.ViewGroup.addView(ViewGroup.java:1871) E/AndroidRuntime( 533): at android.view.ViewGroup.addView(ViewGroup.java:1828) E/AndroidRuntime( 533): at android.view.ViewGroup.addView(ViewGroup.java:1808) E/AndroidRuntime( 533): at android.support.v4.app.NoSaveStateFrameLayout.wrap(NoSaveStateFrameLayout.java:40) E/AndroidRuntime( 533): at android.support.v4.app.FragmentManagerImpl.moveToState(FragmentManager.java:874) E/AndroidRuntime( 533): at android.support.v4.app.FragmentManagerImpl.attachFragment(FragmentManager.java:1240) E/AndroidRuntime( 533): at android.support.v4.app.BackStackRecord.run(BackStackRecord.java:612) E/AndroidRuntime( 533): at android.support.v4.app.FragmentManagerImpl.execPendingActions(FragmentManager.java:1416) E/AndroidRuntime( 533): at android.support.v4.app.FragmentManagerImpl.executePendingTransactions(FragmentManager.java:431) E/AndroidRuntime( 533): at android.support.v4.app.FragmentPagerAdapter.finishUpdate(FragmentPagerAdapter.java:139) E/AndroidRuntime( 533): at android.support.v4.view.ViewPager.populate(ViewPager.java:804) E/AndroidRuntime( 533): at android.support.v4.view.ViewPager.completeScroll(ViewPager.java:1280) E/AndroidRuntime( 533): at android.support.v4.view.ViewPager.computeScroll(ViewPager.java:1176) E/AndroidRuntime( 533): at android.view.ViewGroup.drawChild(ViewGroup.java:1562) E/AndroidRuntime( 533): at android.view.ViewGroup.dispatchDraw(ViewGroup.java:1373) E/AndroidRuntime( 533): at android.view.ViewGroup.drawChild(ViewGroup.java:1644) E/AndroidRuntime( 533): at android.view.ViewGroup.dispatchDraw(ViewGroup.java:1373) E/AndroidRuntime( 533): at android.view.View.draw(View.java:6883) E/AndroidRuntime( 533): at android.widget.FrameLayout.draw(FrameLayout.java:357) E/AndroidRuntime( 533): at android.view.ViewGroup.drawChild(ViewGroup.java:1646) E/AndroidRuntime( 533): at android.view.ViewGroup.dispatchDraw(ViewGroup.java:1373) E/AndroidRuntime( 533): at android.view.ViewGroup.drawChild(ViewGroup.java:1644) E/AndroidRuntime( 533): at android.view.ViewGroup.dispatchDraw(ViewGroup.java:1373) E/AndroidRuntime( 533): at android.view.View.draw(View.java:6883) E/AndroidRuntime( 533): at android.widget.FrameLayout.draw(FrameLayout.java:357) E/AndroidRuntime( 533): at com.android.internal.policy.impl.PhoneWindow$DecorView.draw(PhoneWindow.java:1862) E/AndroidRuntime( 533): at android.view.ViewRoot.draw(ViewRoot.java:1522) E/AndroidRuntime( 533): at android.view.ViewRoot.performTraversals(ViewRoot.java:1258) E/AndroidRuntime( 533): at android.view.ViewRoot.handleMessage(ViewRoot.java:1859) E/AndroidRuntime( 533): at android.os.Handler.dispatchMessage(Handler.java:99) E/AndroidRuntime( 533): at android.os.Looper.loop(Looper.java:130) E/AndroidRuntime( 533): at android.app.ActivityThread.main(ActivityThread.java:3683) E/AndroidRuntime( 533): at java.lang.reflect.Method.invokeNative(Native Method) E/AndroidRuntime( 533): at java.lang.reflect.Method.invoke(Method.java:507) E/AndroidRuntime( 533): at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:839) E/AndroidRuntime( 533): at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:597) E/AndroidRuntime( 533): at dalvik.system.NativeStart.main(Native Method) W/ActivityManager( 68): Force finishing activity com.android.gps/.viewpager.SwipeyTabsSampleActivity W/ActivityManager( 68): Activity pause timeout for HistoryRecord{40716740 com.android.gps/.viewpager.SwipeyTabsSampleActivity} 

谢谢。

编辑:

没有意图进入Map活动,它的工作原理是pwrfect。我的意思是当我使用与历史相同的地图时,没有任何错误。

Solutions Collecting From Web of "如何解决viewpager:指定的子节点已经有父节点。 您必须首先在孩子的父母上调用removeView()"

我也遇到过这个问题。

你可以通过添加单行mViewPager.setOffscreenPageLimit(3);来解决它mViewPager.setOffscreenPageLimit(3);

 public class SwipeyTabsSampleActivity extends FragmentActivity { ... @Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.main); mViewPager = (ViewPager) findViewById(R.id.viewpager); mTabs = (SwipeyTabs) findViewById(R.id.swipeytabs); SwipeyTabsPagerAdapter adapter = new SwipeyTabsPagerAdapter(this, getSupportFragmentManager()); mViewPager.setAdapter(adapter); mViewPager.setOffscreenPageLimit(3); < ------ Add this one } } 

祝你好运。

我使用时遇到了同样的问题

 View res = inflater.inflate(R.layout.fragment_guide_search, container); 

在Fragment.onCreateView里面(…

你必须打电话

 View res = inflater.inflate(R.layout.fragment_guide_search, container, false); 

要么

 View res = inflater.inflate(R.layout.fragment_guide_search, null); 

首先,RB Patel回答插入代码(如下所示)的答案,就像一个魅力,但是当我读到这个function时,我意识到这是一个潜在的优化,实际上并不是bug的解决方案。

 mViewPager.setOffscreenPageLimit(3); 

Android Developer网站对此方法进行了以下说明:

setOffscreenPageLimit(int limit) – 设置在空闲状态下应保留到视图层次结构中当前页面任一侧的页数。

看起来这只是对当前页面右侧或左侧缓存的页面数量设置了限制。 在我的情况下,这只是一个问题的乐队援助,是错误停止和事情顺利,但我仍然有潜伏在我的程序中的坏代码,这些代码根本没有被执行。 我相信这个方法旨在用作优化而不是对bug的实际修复。

我试图在扩展PagerAdapter的自定义类中重载instantiateItem()方法时遇到了这个问题。 在我导航回我之前访问/实例化的选项卡/页面后,我的错误被抛出。

我是Android新手,但我会尽力解释我的解决方案。 抛出此错误的行如下:

 v.addView(child); 

如果我理解正确,那就是窒息,因为孩子之前已经被实例化并被分配了父母。

当我导航回以前访问过的视图/页面时,我试图将已经有父布局视图的视图添加到新布局,因此出错。

解决方案:我刚刚检查了我试图显示的子视图(实例化)是否已经在其他地方实例化,看看它是否有父视图集。 如果已经创建了子视图,那么我只使用子视图的父视图而不是创建新的Layout。

这是我的代码(如果它冒犯了任何专家,我道歉):

 @Override public Object instantiateItem(View container, int position) { LinearLayout v = new LinearLayout(mContext); //the view being loaded (unless it already was then we have to handle it) View child = mViews.get(position); //If the child view was loaded already then it will have a parent view it belongs to //We return the parent view instead of adding the child to the LinearLayout we just created and returning that new layout. if(child.getParent() != null) { View parent = (View) child.getParent(); ((ViewPager) container).addView(parent); return parent; } //first time instantiating a child view/page v.addView(child); // These lines execute the first time a given page is instantiated ((ViewPager) container).addView(v); return v; } 

这是我的解决方案(在每个片段中使用),它既可以平滑又可以避免内存问题:

 ... private LayoutInflater mInflater; private WeakReference mRootView = null; ... @Override public View onCreateView(final LayoutInflater inflater, final ViewGroup container, final Bundle savedInstanceState) { if (inflater != null) mInflater = inflater; else mInflater = LayoutInflater.from(getActivity()); View rootView = mRootView == null ? null : mRootView.get(); if (rootView != null) { final ViewParent parent = rootView.getParent(); if (parent != null && parent instanceof ViewGroup) ((ViewGroup) parent).removeView(rootView); } else { rootView = mInflater.inflate(R.layout.fragment_test, null, false); mRootView = new WeakReference(rootView); } return rootView; } 
 @Override public Object instantiateItem(View arg0, int arg1) { Log.d("instantiateItem", ""+arg0+" "+arg1); try { if(mListViews.get(arg1).getParent()==null) ((ViewPager) arg0).addView(mListViews.get(arg1), 0); else{ // I am new to android, it is strange that the view to be added is already bound to a parent // Through trials and error I solve this problem with the following codes // Add that the element of mlistviews is listview in pagerview; ((ViewGroup)mListViews.get(arg1).getParent()).removeView(mListViews.get(arg1)); ((ViewPager) arg0).addView(mListViews.get(arg1), 0); } } catch (Exception e) { Log.d("parent=", ""+mListViews.get(arg1).getParent()); e.printStackTrace(); } return mListViews.get(arg1); } 

如果你正在使用FragmentPagerAdapter,那么只需在FragmentPagerAdapter中使用destroyItem方法。

 @Override public void destroyItem(ViewGroup container, int position, Object object) { FragmentTransaction ft=fm.beginTransaction(); ft.remove((Fragment) object); ft.commit(); } 

setOffscreenPageLimit(int limit)消耗更多内存,在某些情况下它不能完美运行。 它在任何一方的保留状态见说明。 setOffscreenPageLimit(int limit) – 设置在空闲状态下应保留到视图层次结构中当前页面任一侧的页数。

//如果要添加的子视图已绑定到父级,则从父级中删除子级,然后再次添加到容器中。

 if (v.getParent() != null) { ((ViewGroup) v.getParent()).removeView(v); } container.addView(v);