ViewPage+Fragment 生命周期的研究,以及懒加载的实现
一、ViewPage + Fragment 使用起来很方便。代码量很少。
参考:这个博客
创建三个fragment,添加进去。
二、查看正常情况下的,生命周期。
贴出其中一个fragment的代码,其他都一样(BaseFragmnt暂时是空的,后面用来实现懒加载)。
public class FirstFragment extends BaseFragment{
private static final String TAG = "FirstFragment";
@Nullable
@Override
public View onCreateView(@NonNull LayoutInflater inflater, @Nullable ViewGroup container,
@Nullable Bundle savedInstanceState) {
Log.d(TAG, "onCreateView: ");
return inflater.inflate(R.layout.fragment_first,container,false);
}
@Override
public void onActivityCreated(@Nullable Bundle savedInstanceState) {
super.onActivityCreated(savedInstanceState);
Log.d(TAG, "onActivityCreated: ");
}
@Override
public void onAttach(Context context) {
super.onAttach(context);
Log.d(TAG, "onAttach: ");
}
@Override
public void onAttachFragment(Fragment childFragment) {
super.onAttachFragment(childFragment);
Log.d(TAG, "onAttachFragment: ");
}
@Override
public void setUserVisibleHint(boolean isVisibleToUser) {
super.setUserVisibleHint(isVisibleToUser);
Log.d(TAG, "setUserVisibleHint: " + isVisibleToUser);
}
@Override
public void onCreate(@Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
Log.d(TAG, "onCreate: ");
}
@Override
public void onStop() {
super.onStop();
Log.d(TAG, "onStop: ");
}
@Override
public void onDestroy() {
super.onDestroy();
Log.d(TAG, "onDestroy: ");
}
@Override
public void onPause() {
super.onPause();
Log.d(TAG, "onPause: ");
}
@Override
public void onResume() {
super.onResume();
Log.d(TAG, "onResume: ");
}
@Override
public void onDestroyView() {
super.onDestroyView();
Log.d(TAG, "onDestroyView: ");
}
@Override
public void onHiddenChanged(boolean hidden) {
super.onHiddenChanged(hidden);
Log.d(TAG, "onHiddenChanged: " + hidden);
}
@Override
public void onStart() {
super.onStart();
Log.d(TAG, "onStart: ");
}
@Override
public void onViewCreated(@NonNull View view, @Nullable Bundle savedInstanceState) {
super.onViewCreated(view, savedInstanceState);
Log.d(TAG, "onViewCreated: ");
}
}
(FirstFragment、SecondFragmet、ThreeFragment按顺序添加)
这是点开应用后,所有Fragment的生命周期日志。
很明显,大局来看,只加载了前两个Fragment。
具体的方法上最开始 先走setUserVisibleHint方法 都返回的 false(还没有出现在屏幕上),之后第一个Fragment 的 setUserVisibleHint返回true了。然后按顺序第一个fragment的onAttach -> onCreate,第二个fragment的onAttach -> onCreate,第一个fragment的onCreateView -> onViewCreated -> onActivityCreated -> onStart -> onResume。第二个fragment同样。清晰明了。
viewpage与fragment配合,默认是开启预加载的。默认允许两个fragment同时运行,当滑动到第二个fragment时,会自动预加载第三个fragment。
mainViewPage.setOffscreenPageLimit(2);//通过这个修改
当滑动到第三个页面时,则会将第一个页面被销毁了。(接下来我们看运行是生命周期)
我们滑动到第二个fragment页面。
还是一样,都是先进入 setUserVisibleHint 方法,根据当前页面显示的情况返回true或者false。然后就是第三个fragmen开始初始化,创建。
当我们再滑到第三个页面时
第一个fragment走入了 onPause -> onStop - > onDestroyView 方法,已经被销毁回收了,我们第一个页面上的数据已经不存在了。
当我们再次滑回第二个页面时
第一个页面被重新创建。
我们滑到第一个页面时
第三个页面被销毁。
三、根据实际的应用情况
问题1. :
滑动到第三个页面是第一个页面会被销毁,页面上的数据都会丢失,很不友好,尽管这能减少内存的使用,但正常情况下,宁愿多用点内存,也要保存这个页面。
解决:通过
mainViewPage.setOffscreenPageLimit(3);// 设置成3,或者自己需要长期保存的页面数(最好不超过5个)
问题2. :
进入第一个页面时,会自己加载第二个页面的信息。这样会造成不必要的内存占用。比如我只使用第一个页面,第二个页面我不看,但第二个页面已经创建成功了,数据已经都加载好了,就等着你滑动过去,显示出来了(setUserVisibleHint 方法参数返回true)。这样对于需要使用来说,很友好,滑过去就可以看到,但会占内存,这就需要使用懒加载方法。
解决:Fragment懒加载基类(只针对懒加载,可以根据自己加内容,牛刀油一些。)
BaseFragment
public abstract class BaseFragment extends Fragment {
/**
* 是否已经初始化完成
* 是否已经进入过页面
* 是否正在显示
* */
private boolean isPrepareView,isInitData,isVisibleToUser;
/**
* 第一次进入页面
*/
public void lazyInitData(){
if (!isInitData && isVisibleToUser && isPrepareView) {
isInitData = true;
firstData();
}
}
protected abstract void initData();
protected abstract void firstData();
@Override
public void setUserVisibleHint(boolean isVisibleToUser) {
super.setUserVisibleHint(isVisibleToUser);
this.isVisibleToUser = isVisibleToUser;
if (isInitData){
if (!isVisibleToUser){
// 取消焦点时,做的操作
}else {
// 成功加载后,进入页面所进行的操作
initData();
}
}else {
// 第一次 进入页面 所进行的操作
lazyInitData();
}
}
@Override
public void onActivityCreated(@Nullable Bundle savedInstanceState) {
super.onActivityCreated(savedInstanceState);
initView(); // 布局绑定一些,可以放着,也可以放onCreateView里
// 根据之前的生命周期发现,第一个页面会先走setUserVisibleHint 返回true,再走到该方法创建,所有这里这需要加。
lazyInitData();
}
protected abstract void initView();
@Override
public void onViewCreated(View view, Bundle savedInstanceState) {
super.onViewCreated(view, savedInstanceState);
isPrepareView = true;
}
public abstract int getLayoutId();
@Nullable
@Override
public View onCreateView(@NonNull LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) {
return inflater.inflate(getLayoutId(),container,false);
}
}
FirstFragment
public class FirstFragment extends BaseFragment{
private static final String TAG = "FirstFragment";
@Override
protected void initView() {
Log.d(TAG, "initView: " + "绑定布局中.....");
}
@Override
protected void initData() {
Log.d(TAG, "initData: " + "再次进入页面加载数据.....");
}
@Override
protected void firstData() {
Log.d(TAG, "firstData: " + "第一次进入页面加载数据.....");
}
@Override
public int getLayoutId() {
return R.layout.fragment_first;
}
}