首页 | 新闻 | 新品 | 文库 | 方案 | 视频 | 下载 | 商城 | 开发板 | 数据中心 | 座谈新版 | 培训 | 工具 | 博客 | 论坛 | 百科 | GEC | 活动 | 主题月 | 电子展
返回列表 回复 发帖

Android 保存 Fragment 引用及 getActivity() 为空问题(4)

Android 保存 Fragment 引用及 getActivity() 为空问题(4)

因此取到 Fragment 引用的方法也就找到了:
方法一

既然我们都知道 tag 的生成规则了, 找到 Fragment 那还不是 so easy.
还是以上面的 示例代码1 为例, 获取 fragment1 的引用, 这么做就可以了:

    private void changeFragment1Text() {
        String tag = "android:switcher:" + R.id.view_pager + ":" + 0;
        Fragment1 fragment1 = (Fragment1) getSupportFragmentManager().findFragmentByTag(tag);
        // 一定要做判空, 因为你要找的 Fragment 这时可能还没有加入 Activity 中.
        if (fragment1 != null) {
            fragment1.setText("Laziness is a programmer's feature.");
        } else {
            Log.e("lyux", "fragment not added yet.");
        }
    }

这种方法有两个缺点:
一是, tag 的规则依赖一个源码中的私有方法, 谷歌大大哪天不爽要改了这条规则, 我们的程序就会出错了.
二是, 对于另一个装载 Fragment 的 PagerAdapter, 即 FragmentStatePagerAdapter, 这个方法是不适用的.

    FragmentStatePagerAdapter 是为了懒加载及页面回收的目的而编写的, 即不把每个 page 页的内容都保存在内存里. 因此它在创建了 Fragment 后, 没有给其附加 tag. 所以由它创建的 Fragment 无法用 FragmentManager.findFragmentByTag() 方法找到. 具体见其源码, 也不长.

方法二

还有一种思路, 是重载 FragmentPagerAdapter 类中的 instantiateItem() 方法, 得到 Fragment 引用. 依然以 示例代码1 为例, 将 SlidePagerAdapter 做如下改写即可:

    public class TabChangeActivity extends AppCompatActivity {
     
        private ViewPager mViewPager;
        private Fragment1 mFragment1;
        private Fragment2 mFragment2;
        private Fragment3 mFragment3;
     
        @Override
        protected void onCreate(@Nullable Bundle savedInstanceState) {
            super.onCreate(savedInstanceState);
            setContentView(R.layout.activity_tab_fragment_sample);
            mViewPager = (ViewPager) findViewById(R.id.view_pager);
            mViewPager.setAdapter(new SlidePagerAdapter(getSupportFragmentManager()));
     
            // 延迟5秒改变文字. 如果立刻执行, mFragment1 肯定是 null.
            new Handler().postDelayed(new Runnable() {
                @Override
                public void run() {
                    if (mFragment1 != null) {
                        mFragment1.setText("Every program must have a purpose. If not, it is deleted. -- The Matrix");
                    }
                }
            }, 5000);
        }
     
        private class SlidePagerAdapter extends FragmentPagerAdapter {
     
            public SlidePagerAdapter(FragmentManager fm) {
                super(fm);
            }
     
            @Override
            public Fragment getItem(int position) {
                switch (position) {
                    case 0:
                        return new Fragment1();
                    case 1:
                        return new Fragment2();
                    case 2:
                        return new Fragment3();
                    default:
                        return null; // unlikely to happen
                }
            }
     
            @Override
            public int getCount() {
                return 3;
            }
     
            @Override
            public Object instantiateItem(ViewGroup container, int position) {
                Fragment fragment = (Fragment) super.instantiateItem(container, position);
                switch (position) {
                    case 0:
                        mFragment1 = (Fragment1) fragment;
                        break;
                    case 1:
                        mFragment2 = (Fragment2) fragment;
                        break;
                    case 2:
                        mFragment3 = (Fragment3) fragment;
                        break;
                }
                return fragment;
            }
        }
    }

因为 instantiateItem() 方法管理了 Fragment 的创建及重用, 因此无论其是新创建的, 还是被恢复的, 都可以正确取到引用.

    注意: 不要在 FragmentStatePagerAdapter 场景中使用该方法. 因为我们保存了每一页的 Fragment 的引用, 就会阻止其被回收, 那 FragmentStatePagerAdapter 就白用了: 不就是为了可以回收页面才用它的嘛.
    真要用的话就用 WeakReference<Fragment> 保存其弱引用.
    但据说 4.0 后的 Android 虚拟机中弱引用等于没引用, 会很快被回收掉. (这句是听一位虚拟机大牛说的)
返回列表