ViewPager+Fragment预加载解决方案

来源:互联网 发布:c语言死循环 编辑:程序博客网 时间:2024/05/27 16:43

       之前对ViewPager+Fragment的预加载比较恐惧,只要不要求实现那种左右滑动切换Fragment的效果,我宁可选择4个button+fragment来替换。今天正好有时间看了一下预加载,其实也没那么麻烦。对于预加载,ViewPager的setOffscreenPageLimit的注释写的比较好:

 /**     * Set the number of pages that should be retained to either side of the     * current page in the view hierarchy in an idle state. Pages beyond this     * limit will be recreated from the adapter when needed.     *     * <p>This is offered as an optimization. If you know in advance the number     * of pages you will need to support or have lazy-loading mechanisms in place     * on your pages, tweaking this setting can have benefits in perceived smoothness     * of paging animations and interaction. If you have a small number of pages (3-4)     * that you can keep active all at once, less time will be spent in layout for     * newly created view subtrees as the user pages back and forth.</p>     *     * <p>You should keep this limit low, especially if your pages have complex layouts.     * This setting defaults to 1.</p>     *     * @param limit How many pages will be kept offscreen in an idle state.     */    public void setOffscreenPageLimit(int limit) {        if (limit < DEFAULT_OFFSCREEN_PAGES) {            Log.w(TAG, "Requested offscreen page limit " + limit + " too small; defaulting to "                    + DEFAULT_OFFSCREEN_PAGES);            limit = DEFAULT_OFFSCREEN_PAGES;        }        if (limit != mOffscreenPageLimit) {            mOffscreenPageLimit = limit;            populate();        }    }

       利用预加载,你可以同时使几个页面(3-4)保持活跃,当来回切换页面的时候,你将会消耗更少的时间在布局的创建上,这样切换页面会显得更流畅。但是预加载的页面数要尽可能低,因为当页面布局复杂的话,过多的缓存页面会消耗大量的内存。limit默认值为1,意味着会默认预加载当前页面之前和之后的一个页面,那我们将limit值设置为0不就不预加载了呢,经测试还是会加载的。VIewPager既然提供了这么好的机制,为啥不用呢。这边先写一个demo测试下预加载的机制,用Tablayout+ViewPager+Fragment实现页面和tab的切换效果,代码如下:

布局文件:

<LinearLayout    android:layout_width="match_parent"    android:layout_height="match_parent"    android:orientation="vertical"    xmlns:android="http://schemas.android.com/apk/res/android">  <android.support.design.widget.TabLayout      android:layout_width="match_parent"      android:layout_height="wrap_content"      android:id="@+id/tabLayout"></android.support.design.widget.TabLayout>    <android.support.v4.view.ViewPager        android:layout_width="match_parent"        android:layout_height="match_parent"        android:id="@+id/viewPager">    </android.support.v4.view.ViewPager></LinearLayout>

BaseFragment:主要用于所有Fragment生命周期的打印,注释掉的部分提供了懒加载的解决方案。

public   class BaseFragment extends Fragment{    private static final String TAG ="lifecycle" ;  // private boolean isCanLoadData;    @Override    public void onCreate(@Nullable Bundle savedInstanceState) {        Log.e(TAG,getClass().getName()+"--->"+"onCreate");        super.onCreate(savedInstanceState);    }    @Override    public View onCreateView(LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) {        Log.e(TAG,getClass().getName()+"--->"+"onCreateView");        return super.onCreateView(inflater, container, savedInstanceState);    }    @Override    public void onViewCreated(View view, @Nullable Bundle savedInstanceState) {        super.onViewCreated(view, savedInstanceState);        Log.e(TAG,getClass().getName()+"--->"+"onViewCreated");       // isCanLoadData=true;    }    @Override    public void onResume() {        Log.e(TAG,getClass().getName()+"--->"+"onResume");        super.onResume();//        if(getUserVisibleHint()){//            requestData();//        }    }    @Override    public void onDestroyView() {        Log.e(TAG,getClass().getName()+"--->"+"onDestroyView");        super.onDestroyView();       // isCanLoadData=false;    }    @Override    public void onPause() {        Log.e(TAG,getClass().getName()+"--->"+"onPause");        super.onPause();    }    @Override    public void setUserVisibleHint(boolean isVisibleToUser) {        Log.e(TAG,getClass().getName()+" UserVisible--->"+isVisibleToUser);        super.setUserVisibleHint(isVisibleToUser);//       if(isCanLoadData&&isVisibleToUser){//           requestData();//       }    }//   abstract    void requestData();    @Override    public void onDestroy() {        Log.e(TAG,getClass().getName()+"--->"+"onDestroy");        super.onDestroy();    }}
TabViewPageActivity:4个Fragment代码比较简单就不贴出:
public class TabViewPageActivity extends AppCompatActivity {    private ViewPager viewPager;    private TabLayout tablayout;    @Override    protected void onCreate(Bundle savedInstanceState) {        super.onCreate(savedInstanceState);        setContentView(R.layout.activity_tab_view_page);        initView();        initViewPager();    }    private void initView() {      viewPager=(ViewPager) findViewById(R.id.viewPager);        tablayout=(TabLayout)findViewById(R.id.tabLayout);    }    static class CustomViewPagerAdapter extends FragmentPagerAdapter{        private List<Fragment> fragments=new ArrayList<>();        private List<String> titles;        public CustomViewPagerAdapter(FragmentManager fm) {            super(fm);            initTitle();        }        public  void  addFragment(Fragment fragment){            fragments.add(fragment);        }        @Override        public Fragment getItem(int position) {            return fragments.get(position);        }        private void initTitle() {            titles=new ArrayList<>();            titles.add("First");            titles.add("Second");            titles.add("Third");            titles.add("Four");        }        @Override        public int getCount() {            return fragments.size();        }        @Override        public CharSequence getPageTitle(int position) {            return titles.get(position);        }    }    private void initViewPager(){        CustomViewPagerAdapter customViewPagerAdapter=new CustomViewPagerAdapter(getSupportFragmentManager());        customViewPagerAdapter.addFragment(new FirstFragment());        customViewPagerAdapter.addFragment(new SecondFragment());        customViewPagerAdapter.addFragment(new ThirdFragment());        customViewPagerAdapter.addFragment(new FourFragment());        viewPager.setAdapter(customViewPagerAdapter);        tablayout.setTabMode(TabLayout.MODE_FIXED);        tablayout.setupWithViewPager(viewPager);    }}

  

  运行效果图如下:

  当第一个页面第一次加载时的Log日志:此时创建了FirstFragment和SecondFragment,并且FirstFragment处于用户可见。

12-21 15:00:45.518 2085-2085/com.ormsqlite E/lifecycle: com.ormsqlite.fragment.FirstFragment UserVisible--->false12-21 15:00:45.518 2085-2085/com.ormsqlite E/lifecycle: com.ormsqlite.fragment.SecondFragment UserVisible--->false12-21 15:00:45.518 2085-2085/com.ormsqlite E/lifecycle: com.ormsqlite.fragment.FirstFragment UserVisible--->true12-21 15:00:45.520 2085-2085/com.ormsqlite E/lifecycle: com.ormsqlite.fragment.FirstFragment--->onCreate12-21 15:00:45.520 2085-2085/com.ormsqlite E/lifecycle: com.ormsqlite.fragment.SecondFragment--->onCreate12-21 15:00:45.522 2085-2085/com.ormsqlite E/lifecycle: com.ormsqlite.fragment.FirstFragment--->onCreateView12-21 15:00:45.523 2085-2085/com.ormsqlite E/lifecycle: com.ormsqlite.fragment.FirstFragment--->onViewCreated12-21 15:00:45.523 2085-2085/com.ormsqlite E/lifecycle: com.ormsqlite.fragment.FirstFragment--->onResume12-21 15:00:45.523 2085-2085/com.ormsqlite E/lifecycle: com.ormsqlite.fragment.SecondFragment--->onCreateView12-21 15:00:45.524 2085-2085/com.ormsqlite E/lifecycle: com.ormsqlite.fragment.SecondFragment--->onViewCreated12-21 15:00:45.524 2085-2085/com.ormsqlite E/lifecycle: com.ormsqlite.fragment.SecondFragment--->onResume

   从第一个页面切换到第二个页面时的Log日志:此时创建了ThirdFragment,并且SecondFragment处于用户可见。

12-21 15:07:53.354 2085-2085/com.ormsqlite E/lifecycle: com.ormsqlite.fragment.ThirdFragment UserVisible--->false12-21 15:07:53.355 2085-2085/com.ormsqlite E/lifecycle: com.ormsqlite.fragment.FirstFragment UserVisible--->false12-21 15:07:53.355 2085-2085/com.ormsqlite E/lifecycle: com.ormsqlite.fragment.SecondFragment UserVisible--->true12-21 15:07:53.355 2085-2085/com.ormsqlite E/lifecycle: com.ormsqlite.fragment.ThirdFragment--->onCreate12-21 15:07:53.356 2085-2085/com.ormsqlite E/lifecycle: com.ormsqlite.fragment.ThirdFragment--->onCreateView12-21 15:07:53.359 2085-2085/com.ormsqlite E/lifecycle: com.ormsqlite.fragment.ThirdFragment--->onViewCreated12-21 15:07:53.359 2085-2085/com.ormsqlite E/lifecycle: com.ormsqlite.fragment.ThirdFragment--->onResume
    从第二个页面切换到第三个页面时的Log日志:此时创建了FourFragment,因为只缓存当前界面的之前和之后的页面,此时会销毁FristFragment,并且ThirdFragment处于用户可见。

12-21 15:11:31.050 2085-2085/com.ormsqlite E/lifecycle: com.ormsqlite.fragment.FourFragment UserVisible--->false12-21 15:11:31.050 2085-2085/com.ormsqlite E/lifecycle: com.ormsqlite.fragment.SecondFragment UserVisible--->false12-21 15:11:31.050 2085-2085/com.ormsqlite E/lifecycle: com.ormsqlite.fragment.ThirdFragment UserVisible--->true12-21 15:11:31.050 2085-2085/com.ormsqlite E/lifecycle: com.ormsqlite.fragment.FourFragment--->onCreate12-21 15:11:31.051 2085-2085/com.ormsqlite E/lifecycle: com.ormsqlite.fragment.FirstFragment--->onPause12-21 15:11:31.059 2085-2085/com.ormsqlite E/lifecycle: com.ormsqlite.fragment.FirstFragment--->onDestroyView12-21 15:11:31.060 2085-2085/com.ormsqlite E/lifecycle: com.ormsqlite.fragment.FourFragment--->onCreateView12-21 15:11:31.062 2085-2085/com.ormsqlite E/lifecycle: com.ormsqlite.fragment.FourFragment--->onViewCreated12-21 15:11:31.062 2085-2085/com.ormsqlite E/lifecycle: com.ormsqlite.fragment.FourFragment--->onResume
      从Log中理清了预加载的过程,一个页面加载的时候它总会预加载之前和之后的页面,其他和它无关的页面会被销毁(注意此时调用onDestroyVIew而不会调用onDestroy)。对于当页面从锁屏到解锁以及退到后台再回到前台的时候只会调用onpause,onresume的情况,我想页面在onresume里加载数据。对于预加载的情况,例如从第一个页面到第二个页面,此时在setUserVisibleHint加载数据。因为setUserVisibleHint可能先于onViewCreate之前调用,此时如果加载数据,因为页面没有初始化,会报空指针异常,所以加了一个isCanLoadData标志。具体代码如BaseFragment注释掉代码所示。此时可以将BaseFragment设置成一个抽象类,让其他Framgent实现requestData()这个抽象方法就可以。

    






原创粉丝点击