Android ViewPager缓存原理分析

易娃 等级 213 0 0

前言:

此篇文章讲述了viewpager的基本使用,以及解决和分析刷新不及时的问题,最后是项目中遇到的bug总结,希望对你们有所帮助

一.ViewPager+Fragment的使用

第一步:创建几个fragment
第二步:实例化ViewPager,添加Adapter
第三步:传值绑定

public class MainActivity extends AppCompatActivity {
    private ViewPager mViewPager;
    FragmentManager fragmentManager;
    private List<Fragment> fragments = new ArrayList<>();

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        mViewPager = findViewById(R.id.viewPagerId);
        Fragment1 fragment1 = new Fragment1();
        Fragment2 fragment2 = new Fragment2();
        Fragment3 fragment3 = new Fragment3();
        Fragment4 fragment4 = new Fragment4();
        fragments.add(fragment1);
        fragments.add(fragment2);
        fragments.add(fragment3);
        fragments.add(fragment4);
        fragmentManager = getSupportFragmentManager();
        fragmentManager.beginTransaction();
        mViewPager.setAdapter(new ViewPagerAdapter(fragmentManager));
    }
public class ViewPagerAdapter extends FragmentStatePagerAdapter {

        public ViewPagerAdapter(FragmentManager fm) {
            super(fm);
        }
        @Override
        public Fragment getItem(int i) {
            return fragments.get(i);
        }

        @Override
        public int getCount() {
            return fragments.size();
        }
    } 
二.缓存原理

每次缓存一前一后和当前页面一共三个界面,当界面左边或者右边没有界面的时候,则一共缓存两个界面了。以这种方式加载pager会导致数据刷新不会即时。因为缓存中有的时候就不会从集合中拿,也就不会走生命周期的方法。
解决办法:
Android ViewPager Fragment 切换刷新数据,解决生命周期只走一次的问题

public class Fragment1 extends Fragment {

    @Override
    public View onCreateView(LayoutInflater inflater, ViewGroup container,
                             Bundle savedInstanceState) {
        return inflater.inflate(R.layout.fragment_fragment1, container, false);
    }

    public void onUpdate() {
        Log.d("Tina=======>", "fragment1 " + "onUpdate");
    }

    @Override
    public void setUserVisibleHint(boolean isVisibleToUser) {
        super.setUserVisibleHint(isVisibleToUser);

        if (isVisibleToUser) {
            onUpdate();
        }

    }
} 
分析源码

在FragmentStatePagerAdapter中有一个方法setPrimaryItem,每次切换page的前后都会调用此方法,每次显示当前界面的时候总会调用fragment.setUserVisibleHint(true);因此监听setUserVisibleHint,就可以实现数据刷新了。

public void setPrimaryItem(@NonNull ViewGroup container, int position, @NonNull Object object) {
        Fragment fragment = (Fragment)object;
        if (fragment != this.mCurrentPrimaryItem) {
            if (this.mCurrentPrimaryItem != null) {
                this.mCurrentPrimaryItem.setMenuVisibility(false);
                this.mCurrentPrimaryItem.setUserVisibleHint(false);
            }

            fragment.setMenuVisibility(true);
            fragment.setUserVisibleHint(true);
            this.mCurrentPrimaryItem = fragment;
        }

    } 
三.FragmentPagerAdapter与FragmentStatePagerAdapter的区别

ViewPager中的FragmentPagerAdapter,FragmentStatePagerAdapter 缓存界面的个数是有限的,所以被挤出来的界面是要销毁掉的,FragmentPagerAdapter不会走onDestroy,所以不会完全被回收,但是FragmentStatePagerAdapter会走ondestroy彻底销毁掉。

四.Viewpager自动轮播

viewPager自动轮播的实现网上估计很多,这里的注意点发生的情景为轮播图的数量会发生变化的情况,在使用hander发送消息的时候,需要注意一点,要不然会使得项目崩溃。

 if (mHandler == null) {
            mHandler = new Handler() {
                @Override
                public void handleMessage(Message msg) {
                    // 得到当前的页面
                    int currentItem = pager.getCurrentItem();
                    // 确定下一个页面
                    //如果轮播图为空
                    if (data.getSlider() == null || data.getSlider().isEmpty()) {
                    } else {
                        pager.setVisibility(View.VISIBLE);
                        if (currentItem < data.getSlider().size() - 1) {
                            currentItem++;
                        } else {
                            currentItem = 0;
                        }
                    }
                    // 设置页面
                    if (currentItem == 0 || data.getSlider().size() - 1 < currentItem) {
                        pager.setCurrentItem(0, false);
                    } else {
                        pager.setCurrentItem(currentItem);
                    }
                    //mScroller.setmDuration(800);
                    // 给自己发消息
                    mHandler.sendEmptyMessageDelayed(0, 3600);
                }
            };
            mHandler.sendEmptyMessageDelayed(0, 5600);
        } 

注意第19行,如果不判断currentItem是否越界,则会出现崩溃。因为,如果轮播图的个数从4减少到2,当轮播图自动滑到了第二张,此时currentItem计算完后值为2,也就是接下来会显示第三张,但是data中只有两个数据已经没有第三张了,故setCurrentItem(2)的时候,数组会发生越界,导致崩溃。
喵印~~

收藏
评论区