首先扯点别的:今天买回家的火车票,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