Fragment 懒加载

首先扯点别的:今天买回家的火车票,12306还是没让我失望,果断没有抢到。先买了一个飞机票,然后等着抢明天的火车票,如果抢到了就把飞机票退了,不然就得坐飞机了。

今天记录一下 Fragment 懒加载

关于Fragment的懒加载有以下两点先声明一下:

1.Fragment 的 setUserVisibleHint方法, 只有 Fragment 在 ViewPager 里才会被调用

//如果isVisibleToUser为true,表示当前界面对用户可见
 @Override
    public void setUserVisibleHint(boolean isVisibleToUser) {
        super.setUserVisibleHint(isVisibleToUser);

    }

2.Fragment 的 setUserVisibleHint 的执行在 onCreateView 之前

懒加载:Fragment在ViewPager中使用的时候,当Fragment对用户可见的时候才加载数据,这样可以减少Activity启动的时候所需要的资源,想一想,要是一启动Activity,就有多个Fragment一起加载数据,肯定要需要大量的资源。

实现步骤

1.定义BaseLazyFrament

public abstract class BaseLazyFragment extends Fragment {

    protected String TAG = getClass().getSimpleName();

    //标记布局是否已经初始化完毕
    protected boolean isViewCreated;
    //标记是否已经加载过数据
    protected boolean isLoadDataCompleted;
    /**
     * 声明rootView,当Fragment调用 onCreateView 时创建rootView,
     * 当Fragment切换为不可见并调用了 onDestroyView 销毁视图的时候,
     * 这个rootView并不会被销毁。当Fragment 重新切换回来并调用onCreateView重新创建视图
     * 的 时候,直接返回rootView.
     */
    protected View rootView;
    //这个是为了用在子类显示数据的
    protected RecyclerView rv;

    public BaseLazyFragment() {
    }

    @Override
    public void setUserVisibleHint(boolean isVisibleToUser) {
        super.setUserVisibleHint(isVisibleToUser);
        Log.e(TAG, "isVisibleToUser=" + isVisibleToUser);
        //如果当前Fragment可见,onCreateView 已经调用完毕,并且没有加载过数据,则加载数据
        if (isVisibleToUser && isViewCreated && !isLoadDataCompleted) {
            lazyLoadData();
        }
    }

    @Override
    public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
        if (rootView == null) {
            rootView = inflater.inflate(getLayout(), container, false);
            ButterKnife.bind(this, rootView);
            init(rootView);
            //isViewCreated 置为 true
            isViewCreated = true;
        }
        return rootView;
    }

    /**
     *
     * 在这里要调用一次lazyLoadData ,因为ViewPage展示第一页的时候setUserVisibleHint 
     * 先于 onCreateView调用,这时候 isViewCreated 为false,不会加载数据。
     * onActivityCreated 在 onCreateView 之后调用,这时候视图已经初始化完
     * 毕 isViewCreated 为 true,所以我们在这里加载数据,保证第一页Fragment正常显示
     */
    @Override
    public void onActivityCreated(@Nullable Bundle savedInstanceState) {
        super.onActivityCreated(savedInstanceState);
        if (getUserVisibleHint()) {
            lazyLoadData();
        }
    }

    //获取布局文件
    protected abstract int getLayout();

    //初始化一些view和相关数据
    protected abstract void init(View view);

    //加载数据
    protected void lazyLoadData() {
        isLoadDataCompleted = true;
    }

}

代码中使用了ButterKnife 进行view绑定,有一点需要说明一下:声明 成员变量 rootView,用来保存Fragment的视图,如果在onCreateView声明局部变量rootView(如下所示),那么在Fragment 调用onDestroyView以后,用户切换回来 onCreateView 重新调用,会导致一些问题。

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

举个例子: 初始的时候,Fragment第一次可见,Fragment中有一个RecylerView,我们给它设置了一个adapter。然后我们切换Fragment,导致当前Fragment不可见,并且视图被销毁了。那么我们重新切换回来后,Fragment会重新创建视图(调用onCreateView),然后我们这个时候调用 adapter.notifyDataSetChanged();发现完全没有作用。因为我们重新创建视图以后,会重新创建RecylerView实例。这个RecylerView已经不是我们设置过adapter的RecylerView了,所以调用 adapter.notifyDataSetChanged()完全没有作用。关于调用 adapter.notifyDataSetChanged()不起作用的更详细的讨论请看这里 RecyclerView遇到notifyDataSetChanged无效时的解决方案

2.定义完了BaseLazyFrament,然后我们定义Fragment实现它基本就可以了,下面的代码中的getData方法在lazyLoadData中调用,模拟加载数据而已。

public class FirstLazyFragment extends BaseLazyFragment {

    public static final String ID = "ID";
    protected String TAG = getClass().getSimpleName();
    @BindView(R.id.ptr_rv)
    PullToRefreshRecyclerView pullToRefreshRecyclerView;
    @BindView(R.id.tv_title)
    TextView tvTitle;

    private int id = -1;

    private List<NotifyBean> data;
    private NotifyAdapter adapter;

    public FirstLazyFragment() {
        // Required empty public constructor
    }

    public static FirstLazyFragment newInstance(int id) {
        FirstLazyFragment fragment = new FirstLazyFragment();
        Bundle args = new Bundle();
        args.putInt(ID, id);
        fragment.setArguments(args);
        return fragment;
    }

    @Override
    public void onCreate(@Nullable Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        if (getArguments() != null) {
            id = getArguments().getInt(ID);
        }
    }

    @Override
    protected int getLayout() {
        return R.layout.fragment_lazy;
    }

    @Override
    protected void init(View view) {
        Log.e(TAG, "onCreateView init id=" + id);
        tvTitle.setText("fragment id is " + id);
        data = new ArrayList<>();
        rv = pullToRefreshRecyclerView.getRefreshableView();
        rv.setLayoutManager(new LinearLayoutManager(getContext()));
        adapter = new NotifyAdapter(data);
        rv.setAdapter(adapter);
        pullToRefreshRecyclerView.setOnRefreshListener(new PullToRefreshBase.OnRefreshListener<RecyclerView>() {
            @Override
            public void onRefresh(PullToRefreshBase<RecyclerView> refreshView) {
                getData();
            }
        });
    }

    @Override
    protected void lazyLoadData() {
        super.lazyLoadData();
        Log.e(TAG, "lazyLoadData id=" + id);
        getData();
    }

    private void getData() {
        pullToRefreshRecyclerView.postDelayed(new Runnable() {
            @Override
            public void run() {
                pullToRefreshRecyclerView.onRefreshComplete();
                if (page <= 3) {
                    List<NotifyBean> tempList = new ArrayList<>();
                    for (int i = 0; i < 10; i++) {
                        NotifyBean notifyBean = new NotifyBean(System.currentTimeMillis() / 1000, "page" + page + "i=" + i);
                        tempList.add(notifyBean);
                    }
                    data.addAll(tempList);
                    page++;
                    adapter.notifyDataSetChanged();
                } else {
                    Toast.makeText(getContext(), getString(R.string.load_all), Toast.LENGTH_SHORT).show();
                    pullToRefreshRecyclerView.setMode(PullToRefreshBase.Mode.DISABLED);
                }
            }
        }, 500);
    }
}

3.别忘了,懒加载是Fragment在ViewPager中使用的。定义ViewPager的适配器

public class ViewPagerAdapter extends FragmentStatePagerAdapter {

    private List<Fragment> fragments;

    public ViewPagerAdapter(FragmentManager fm, List<Fragment> fragments) {
        super(fm);
        this.fragments = fragments;
    }

    @Override
    public Fragment getItem(int position) {
        return fragments.get(position);
    }

    @Override
    public int getCount() {
        return fragments.size();
    }

}

4.在Activity中使用

public class LazyLoadActivity extends AppCompatActivity {

    @BindView(R.id.view_page)
    ViewPager viewPage;
    private List<Fragment> fragments;

    public static void launch(Context context) {
        Intent intent = new Intent(context, LazyLoadActivity.class);
        context.startActivity(intent);
    }

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_lazy_load);
        ButterKnife.bind(this);
        fragments = new ArrayList<>();
        fragments.add(FirstLazyFragment.newInstance((1)));
        fragments.add(SecondLazyFragment.newInstance((2)));
        fragments.add(ThirdLazyFragment.newInstance((3)));
        fragments.add(ForthLazyFragment.newInstance((4)));
        viewPage.setAdapter(new ViewPagerAdapter(getSupportFragmentManager(), fragments));
    }
}

完整的代码请移步至:https://github.com/humanheima/FragmentUseDemo,下面那句话很重要

demo中的lazyload文件夹下就是实现懒加载的所有代码

参考链接
1.https://www.jianshu.com/p/8a0f6b627e37
2.http://www.10tiao.com/html/169/201608/2650820834/1.html
3.http://www.jcodecraeer.com/a/anzhuokaifa/androidkaifa/2014/1021/1813.html

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值