懒加载的目的主要是应用于在装有多个Fragment并进行切换的时候,如viewPager。相信各位在写项目的时候,肯定也有遇到过viewpager里的fragment进行了前后预加载,即3个fragment的数据加载,要通过setOffscreenPageLimit来设置预加载的项目,不设置setOffscreenPageLimit,则默认为1(设置0无效,可以查看该方法源码知道),即时设置了让他预加载为0了,也会执行多个预加载。这个很让人头疼,即大大降低了性能,又浪费初始化资源。然而我们采用懒加载技术就能让用户看到的页面才会加载他的数据,大大提高效率。
懒加载的实现原理就是利用Fragment中的setUserVisibleHint()和onCreateView(),主要是利用了setUserVisibleHint()对fragment的可见状态监测和在oncreateView()前执行的优点。注意加载时,如果这个fragment不可见的加载,那setUserVisibleHint()没有执行。
当viewPager中fragment改变可见状态, 使用getUserVisibleHint() 可以返回fragment是否可见状态:从可见到不见,为false;从不可见切换到可见,为true。
可见如图:具体参考博客****http://blog.csdn.net/mr_immortalz/article/details/51015196
注意:滑动到第三个fragment时,第一个fragment移除了相关的视图但未和活动解除关联。所以从3滑回2时,预加载的1的生命周期少一些执行。
下面我们来看懒加载BaseLazyFragment的class代码:
1、首先看setUserVisibleHint()方法的重写。
![](https://img.haomeiwen.com/i3161958/0f62bff42c100fb6.png)
第一个判断语句主要是两个判断条件
1)当isVisibleToUser 为true则进行数据加载,当isVisibleToUser为false则不进行数据加载2)判断isInit值,对于已经加载过数据的fragment,再次被滑动到也不在进行加载数据,也就是每个fragment仅做一次数据加载工作第二个判断语句是针对以初始化的fragment,再根据是否可见来判断显示、执行生命周期。
2、然后回到onCreateView()上。在onCreateView()里,对要懒加载的fragment是添加FrameLayout。
![](https://img.haomeiwen.com/i3161958/8dba2601de9aceed.png)
如我注释所写,应该比较好理解的吧?(一开始我看了几篇文章还是很混,直到看了(http://blog.csdn.net/mr_immortalz/article/details/51015196的生命周期演示后,就大体上有个了解了,各位可以看看。)
3、然后是对fragment生命周期的处理,每个状态下以Fragment的回调方法名字后面要加个Lazy的方法名命名,并依此调用。
注意:onFragmentStopLazy()、onFragmentStartLazy()、onResumeLazy()在其他地方也有调用的。
![](https://img.haomeiwen.com/i3161958/e91248a048e90f4b.png)
4、加载view,我们在onCreateView()里,对要懒加载的fragment是,添加FrameLayout,设置setContentView()是为了当我们将fragment移至可见,则能够根据判断,替换掉原来的FrameLayout布局。因为,移至可见时,该fragment会再次调用onCreateView()方法嘛。
![](https://img.haomeiwen.com/i3161958/9e0e89f1f2ef5d03.png)
最后,我贴一下我的代码,代码开头注释里讲了整体的怎么懒加载思考思路。
package android.davidnba.com.davidnba_ywh.base;
import android.davidnba.com.davidnba_ywh.widget.LoadingDialog;
import android.os.Bundle;
import android.util.Log;
import android.view.View;
import android.view.ViewGroup;
import android.widget.FrameLayout;
/* Created by 仁昌居士 on 2017/2/6.
* 懒加载Fragment</h1> 只有创建并显示的时候才会调用onCreateViewLazy方法
* 懒加载的原理onCreateView的时候Fragment有可能没有显示出来。
* 但是调用到setUserVisibleHint(boolean isVisibleToUser),isVisibleToUser =
* true的时候就说明有显示出来
* 但是要考虑onCreateView和setUserVisibleHint的先后问题所以才有了下面的代码
* 注意:
* 《1》原先的Fragment的回调方法名字后面要加个Lazy,比如Fragment的onCreateView方法, 就写成onCreateViewLazy
* 《2》使用该LazyFragment会导致多一层布局深度
*/
/* fragment一共四种情况:
可见、初始化;
可见、未初始化;
不可见、初始化;
不可见、未初始化;
逻辑分析,假设setOffscreenPageLimit(1),共预加载2个fragment:
刚进来,1是可见,且要初始化的,2是不可见、未初始化,第三个3是不绑定到activity的。
于是,1走途径1,2走途径2.
然后,假设滑动了,1滑到2。
此时,1不可见,且已初始化了,2是可见,将要初始化,3绑定到activity上,为不可见、未初始化。
于是,1由于预加载的原因,未解除与视图的联系。所以onPause()、onStop()、onDestoryView()未执行,
并且,由于1不可见,setUserVisibleHint()执行了。所以, isStart设置为false,即不可见;并调用onFragmentStopLazy();
2可见,同理由于预加载原因,处于可见状态时,不会再调用onCreateView(),而是会调用setUserVisibleHint(),
所以,isStart设置为true;onFragmentStartLazy();
3呢,调用onCreateView(),又由于3不可见且未初始化,则不执行。所以,加载的是个FrameLayout
*/
public class BaseLazyFragment extends BaseFragment {
private boolean isInit = false;//真正要显示的View是否已经被初始化(正常加载)
private Bundle savedInstanceState;
public static final String INTENT_BOOLEAN_LAZYLOAD = "intent_boolean_lazyload";
private boolean isLazyLoad = true;
private FrameLayout layout;
public LoadingDialog mLoadingDialog;
private boolean isStart = false;//是否处于可见状态,in the screen
@Override
protected void onCreateView(Bundle saveInstanceState) {
super.onCreateView(saveInstanceState);
Bundle bundle = getArguments();
if (bundle != null) {
isLazyLoad = bundle.getBoolean(INTENT_BOOLEAN_LAZYLOAD, isLazyLoad);
}
//判断是否懒加载
if (isLazyLoad) {
//一旦isVisibleToUser==true即可对真正需要的显示内容进行加载
if (getUserVisibleHint() && !isInit) {
//途径1
this.savedInstanceState = saveInstanceState;
onCreateViewLazy(saveInstanceState);
isInit = true;
} else {
//途径2
//如果不可见或者已经初始化了
//进行懒加载
layout = new FrameLayout(getApplicationContext());
layout.setLayoutParams(new ViewGroup.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.MATCH_PARENT));
super.setContentView(layout);
}
} else {
//途径3
//这里是不可见,但已经初始化了
//不需要懒加载,开门江山,调用onCreateViewLazy正常加载显示内容即可
onCreateViewLazy(saveInstanceState);
isInit = true;
}
}
@Override
public void setUserVisibleHint(boolean isVisibleToUser) {
super.setUserVisibleHint(isVisibleToUser);
//一旦isVisibleToUser==true即可进行对真正需要的显示内容的加载
//判断fragment是否可见,是否还未被初始化,该fragment布局是否存在
//可见,但还没被初始化,且该fragment布局存在
if (isVisibleToUser && !isInit && getContentView() != null) {
isInit = true; //允许初始化
onCreateViewLazy(savedInstanceState);//调用懒加载
onResumeLazy();
}
//对于已经加载过数据的fragment,再次被滑动到也不在进行加载数据,也就是每个fragment仅做一次数据加载工作
//如果已经初始化了,且该fragment布局存在
if (isInit && getContentView() != null) {
if (isVisibleToUser) {
isStart = true;
onFragmentStartLazy();
} else {
isStart = false;
onFragmentStopLazy();
}
}
}
protected void onCreateViewLazy(Bundle savedInstanceState) {
Log.d("TAG", "onCreateViewLazy() called with: " + "savedInstanceState = [" + savedInstanceState + "]");
}
//当Fragment被滑到不可见的位置时,调用
protected void onFragmentStopLazy() {
Log.d("TAG", "onFragmentStopLazy() called with: " + "");
}
//当Fragment被滑到可见的位置时,调用
protected void onFragmentStartLazy() {
Log.d("TAG", "onFragmentStartLazy() called with: " + "");
}
protected void onResumeLazy() {
Log.d("TAG", "onResumeLazy() called with: " + "");
}
protected void onPauseLazy() {
Log.d("TAG", "onPauseLazy() called with: " + "");
}
protected void onDestroyViewLazy() {
}
@Deprecated
@Override
public final void onStart() {
Log.d("TAG", "onStart() : " + "getUserVisibleHint():" + getUserVisibleHint());
super.onStart();
if (isInit && !isStart && getUserVisibleHint()) {
isStart = true;
onFragmentStartLazy();
}
}
@Deprecated
@Override
public final void onStop() {
super.onStop();
Log.d("TAG", "onStop() called: " + "getUserVisibleHint():" + getUserVisibleHint());
if (isInit && isStart && getUserVisibleHint()) {
isStart = false;
onFragmentStopLazy();
}
}
@Override
@Deprecated
public final void onResume() {
Log.d("TAG", "onResume() : " + "getUserVisibleHint():" + getUserVisibleHint());
super.onResume();
if (isInit) {
onResumeLazy();
}
}
@Override
@Deprecated
public final void onPause() {
Log.d("TAG", "onPause() : " + "getUserVisibleHint():" + getUserVisibleHint());
super.onPause();
if (isInit) {
onPauseLazy();
}
}
@Override
@Deprecated
public final void onDestroyView() {
Log.d("TAG", "onDestroyView() : " + "getUserVisibleHint():" + getUserVisibleHint());
super.onDestroyView();
if (isInit) {
onDestroyViewLazy();
}
isInit = false;
}
@Override
public void setContentView(int layoutResID) {
//判断若isLazyLoad==true,移除所有lazy view,加载真正要显示的view
if (isLazyLoad && getContentView() != null && getContentView().getParent() != null) {
layout.removeAllViews();
View view = inflater.inflate(layoutResID, layout, false);
layout.addView(view);
}
//否则,开门见山,直接加载真正要显示的view
else {
super.setContentView(layoutResID);
}
}
@Override
public void setContentView(View view) {
//判断若isLazyLoad==true,移除所有lazy view,加载真正要显示的view
if (isLazyLoad && getContentView() != null && getContentView().getParent() != null) {
layout.removeAllViews();
layout.addView(view);
}
//否则,开门见山,直接加载真正要显示的view
else {
super.setContentView(view);
}
}
}
参考博客:
[http://blog.csdn.net/mr_immortalz/article/details/51015196]
http://blog.csdn.net/sinat_15877283/article/details/51037987
http://www.jianshu.com/p/58fd611260b5
http://www.open-open.com/lib/view/open1477033083443.html
网友评论