如何在两个片段之间切换,而不是每次重新创build片段?

我正在开发一个android应用程序,它使用导航抽屉在两个片段之间切换。 但是,每次切换时,片段都被完全重新创build。

这是我主要活动的代码。

/* The click listener for ListView in the navigation drawer */ private class DrawerItemClickListener implements ListView.OnItemClickListener { @Override public void onItemClick(AdapterView<?> parent, View view, int position, long id) { selectItem(position); } } private void selectItem(int position) { android.support.v4.app.Fragment fragment; String tag; android.support.v4.app.FragmentManager; fragmentManager = getSupportFragmentManager(); switch(position) { case 0: if(fragmentManager.findFragmentByTag("one") != null) { fragment = fragmentManager.findFragmentByTag("one"); } else { fragment = new OneFragment(); } tag = "one"; break; case 1: if(fragmentManager.findFragmentByTag("two") != null) { fragment = fragmentManager.findFragmentByTag("two"); } else { fragment = new TwoFragment(); } tag = "two"; break; } fragment.setRetainInstance(true); fragmentManager.beginTransaction().replace(R.id.container, fragment, tag).commit(); // update selected item and title, then close the drawer mDrawerList.setItemChecked(position, true); setTitle(mNavTitles[position]); mDrawerLayout.closeDrawer(mDrawerList); } 

我已经设置了一些debugging日志logging,并且每次调用selectItem时,都会销毁一个碎片,而创build另一个碎片。

有没有什么办法来防止碎片被重新创build,而只是重用它们呢?

Solutions Collecting From Web of "如何在两个片段之间切换,而不是每次重新创build片段?"

在@meredrica指出replace()销毁碎片之后,我回到了FragmentManager文档。 这是我提出的解决scheme,似乎工作。

 /* The click listener for ListView in the navigation drawer */ private class DrawerItemClickListener implements ListView.OnItemClickListener { @Override public void onItemClick(AdapterView<?> parent, View view, int position, long id) { selectItem(position); } } private void selectItem(int position) { android.support.v4.app.FragmentManager; fragmentManager = getSupportFragmentManager(); switch(position) { case 0: if(fragmentManager.findFragmentByTag("one") != null) { //if the fragment exists, show it. fragmentManager.beginTransaction().show(fragmentManager.findFragmentByTag("one")).commit(); } else { //if the fragment does not exist, add it to fragment manager. fragmentManager.beginTransaction().add(R.id.container, new OneFragment(), "one").commit(); } if(fragmentManager.findFragmentByTag("two") != null){ //if the other fragment is visible, hide it. fragmentManager.beginTransaction().hide(fragmentManager.findFragmentByTag("two")).commit(); } break; case 1: if(fragmentManager.findFragmentByTag("two") != null) { //if the fragment exists, show it. fragmentManager.beginTransaction().show(fragmentManager.findFragmentByTag("two")).commit(); } else { //if the fragment does not exist, add it to fragment manager. fragmentManager.beginTransaction().add(R.id.container, new TwoFragment(), "two").commit(); } if(fragmentManager.findFragmentByTag("one") != null){ //if the other fragment is visible, hide it. fragmentManager.beginTransaction().hide(fragmentManager.findFragmentByTag("one")).commit(); } break; } // update selected item and title, then close the drawer mDrawerList.setItemChecked(position, true); setTitle(mNavTitles[position]); mDrawerLayout.closeDrawer(mDrawerList); } 

我也添加了这一点,但我不知道是否有必要。

 @Override public void onDestroy() { super.onDestroy(); FragmentManager fragmentManager = getSupportFragmentManager(); if(fragmentManager.findFragmentByTag("one") != null){ fragmentManager.beginTransaction().remove(fragmentManager.findFragmentByTag("one")).commit(); } if(fragmentManager.findFragmentByTag("two") != null){ fragmentManager.beginTransaction().remove(fragmentManager.findFragmentByTag("two")).commit(); } } 

对标签使用attach / detach方法:

分离将破坏视图的stream畅,但保持状态,就像在后台一样; 这将使“不可见”片段具有较小的内存占用。 但是请注意,您需要正确实施片段生命周期(您应该首先完成)

从UI中分离给定的片段。 这与将其放在后端堆栈上时的状态相同:将片段从UI中删除,但其状态仍由片段pipe理器主动pipe理。 进入这个状态时,它的视图层次被破坏。

第一次添加片段

 FragmentTransaction t = getSupportFragmentManager().beginTransaction(); t.add(android.R.id.content, new MyFragment(),MyFragment.class.getSimpleName()); t.commit(); 

那么你分开它

 FragmentTransaction t = getSupportFragmentManager().beginTransaction(); t.detach(MyFragment.class.getSimpleName()); t.commit(); 

如果切换回来,再次连接,状态将被保留

 FragmentTransaction t = getSupportFragmentManager().beginTransaction(); t.attach(getSupportFragmentManager().findFragmentByTag(MyFragment.class.getSimpleName())); t.commit(); 

但是你总是要检查片段是否被添加,如果没有,那么添加它,否则就附加它:

 if (getSupportFragmentManager().findFragmentByTag(MyFragment.class.getSimpleName()) == null) { FragmentTransaction t = getSupportFragmentManager().beginTransaction(); t.add(android.R.id.content, new MyFragment(), MyFragment.class.getSimpleName()); t.commit(); } else { FragmentTransaction t = getSupportFragmentManager().beginTransaction(); t.attach(getSupportFragmentManager().findFragmentByTag(MyFragment.class.getSimpleName())); t.commit(); } 

replace方法破坏你的碎片。 一个解决方法是将它们设置为Visibility.GONE ,另一个(不太容易)的方法是将它们保存在一个variables中。 如果你这样做,确保你不会左右泄漏内存。

我之前是这样做的:

  if (mPrevFrag != fragment) { // Change FragmentTransaction ft = fragmentManager.beginTransaction(); if (mPrevFrag != null){ ft.hide(mPrevFrag); } ft.show(fragment); ft.commit(); mPrevFrag = fragment; } 

(你需要在这个解决scheme中跟踪你的前面的片段)

这是一个有点迟到的回应。 如果您使用视图分页器查看分片,请将分片的屏幕外页面限制设置为创build的分片数量。

 mViewPager.setOffscreenPageLimit(3); // number of fragments here is 3 

我想你不能直接操纵你的Fragments的生命周期机制。 你可以findFragmentByTag事实并不是很糟糕。 这意味着Fragment对象没有完全重新创build,如果它已经被提交。 现有的Fragment只是传递每个Fragment所有的生命周期步骤 – 这意味着只有UI被“重新创build”。

这是一个非常方便和有用的内存pipe理策略 – 在大多数情况下是合适的。 已经消失的Fragment具有必须利用的资源以便取消分配内存。

如果你只是停止使用这个策略,你的应用程序的内存使用可能会严重增加。

尽pipe如此,仍然存在保留的片段 ,其生命周期有点不同,并且不符合他们所附的活动。 通常,它们用于保留一些您想要保存的内容,例如pipe理configuration更改

然而,片段创build策略取决于上下文 – 也就是说,你想要解决什么问题,以及你愿意接受哪些权衡。

和Tester101一样的想法,但这是我最终使用的。

  FragmentManager fragmentManager = getSupportFragmentManager(); FragmentTransaction fragmentTransaction = fragmentManager.beginTransaction(); Fragment oldFragment = fragmentManager.findFragmentByTag( "" + m_lastDrawerSelectPosition ); if ( oldFragment != null ) fragmentTransaction.hide( oldFragment ); Fragment newFragment = fragmentManager.findFragmentByTag( "" + position ); if ( newFragment == null ) { newFragment = getFragment( position ); fragmentTransaction.add( R.id.home_content_frame, newFragment, "" + position ); } fragmentTransaction.show( newFragment ); fragmentTransaction.commit(); 

如何玩Visible属性?