【问题标题】:One Activity, multiple Fragments and setRetainInstance一个 Activity,多个 Fragments 和 setRetainInstance
【发布时间】:2013-01-17 13:31:55
【问题描述】:

在我的应用程序中,我使用了一个活动和两个片段。该应用程序使用带有容器的布局,因此片段是通过事务添加的。第一个片段包含一个列表视图,另一个片段包含列表视图项的详细视图。 两个片段都使用 setRetainInstance(true)。通过替换事务添加片段并设置 addToBackStack(null)。 listfragment 包含一个实例变量,其中包含列表的一些信息。现在我更改为详细信息并按回,实例变量为空。我阅读了 setRetainInstance 和 addToBackStack 并删除了 addToBackStack,但即便如此,实例变量也是空的。

有人知道我做错了什么吗?

问候, 托马斯

【问题讨论】:

    标签: android android-fragments


    【解决方案1】:

    setRetainInstance(true) 将告诉FragmentManager 在包含Activity 的内容因某种原因被杀死并重建时保留该片段。它不能保证 Fragment 实例在添加或替换事务后会继续存在。听起来您的适配器正在被垃圾收集,而您没有创建新的。

    一个更普遍的简单解决方案是制作一个看不见的Fragment 以保留您的ListAdapter。这样做的方法是创建Fragment,将retain 实例设置为true,并在方法onCreateView() 中返回null。要添加它,只需通过FragmentTransaction 调用addFragment(Fragment, String)。您永远不会删除或替换它,因此它会在应用程序的整个时间内始终保留在内存中。屏幕旋转不会杀死它。

    每当您的ListFragment 被创建时,在onCreateView() 中获取FragmentManager 并使用findFragmentById()FindFragmentByTag() 方法从内存中检索您保留的片段。然后从该片段中获取适配器并将其设置为列表的适配器。

    public class ViewlessFragment extends Fragment {
    
       public final static string TAG = "ViewlessFragment";
    
       private ListAdapter mAdapter;
    
       @Override
       public ViewlessFragment() {
          mAdapter = createAdater();
          setRetainInstance(true);
       }
    
       @Override
       public void onCreateView (LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
          return null;
       }
    
       public ListAdapter getAdapter() {
          return mAdapter;
       }
    }
    
    public class MyListFragment extends ListFragment {
    
       final public static String TAG = "MyListFragment";
    
       @Override
       public void onCreateView (LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
          final View returnView = getMyView();
          final ViewlessFragment adapterFragment = (ViewlessFragment) getFragmentManager().findFragmentByTag(ViewlessFragment.TAG);
          setListAdapter(ViewlessFragment.getAdapter());
          return returnView;
       }
    }
    
    public class MainActivity extends FragmentActivity {
    
       @Override
       public void onCreate(Bundle icicle) {
          // ... setup code...
          final FragmentManager fm = getSupportFragmentManager();
          final FragmentTransaction ft = fm.beginTransaction();
          ViewlessFragment adapterFragment = fm.findFragmentByTag(ViewlessFragment.TAG);
          if(adapterFragment == null) {
             ft.add(new ViewlessFragment(), ViewlessFragment.TAG);
          }
          ft.add(R.id.fragmentContainer, new MyListFragment(), MyListFragment.TAG);
          ft.commit();
       }
    }
    

    【讨论】:

    • 感谢您的想法,无视图片段听起来不错。今晚会试试这个。
    • 所以这个无视图片段与当前显示的片段平行运行,并在需要时提供信息,对吧?
    • “并行运行”从编程的角度来看是一个不好的术语,但是是的。它保留在内存中,因为您永远不会从FragmentManager 中删除它。由于适配器和适配器的数据是在构造函数中创建的,所以它只在创建新实例时创建一次。然后只需调用getAdapter() 即可检索该适配器。每当新的ListView 因任何原因被夸大时,数据就会出现。
    • 虽然它在技术上是可行的,但我仍然想知道使用 Fragments 作为存储“全局”信息的一种方式是否是个好主意。仅使用 Application 子类甚至使用静态成员听起来开销更少?
    • 这种方法的一个警告:确保在方向更改期间不会泄漏内存。我一直在用新的RecyclerView 对此进行测试,并且片段中的适配器保留了对 UI 视图的引用,而这些引用又保留了对活动的引用。我对此问题的解决方法是在 UI 片段的 onDestroyView() 中调用 recyclerView.setAdapter(null)
    猜你喜欢
    • 2017-04-27
    • 1970-01-01
    • 1970-01-01
    • 2022-01-14
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多