自从实习以来一直在忙着赶项目进度,没有时间(懒)总结。现在终于有空总结一下这两个多月的收获了。从性能优化中的fragment懒加载开始梳理吧。
项目中使用ViewPager+Fragment,拿练手项目xMusic来说吧,在MainActivity中有两个fragment,一个是本地播放页面,一个是“发现”页面,“发现”页面包含广告轮播图和推荐歌单,图片资源比较多。正常打开app时两个fragment都会进行网络请求加载资源。刚打开app的时候,内存占用能上到88-90m。对于很大一部分只听本地歌曲的用户来说,加载“发现”页面不仅占用内存,还消耗网络资源。
ViewPager中有一个方法 setOffscreenPageLimit(int limit) 可以设置预加载的页面数量。通过源码我们可以知道,这个方法设置的limit最终都不会小于1。因此对于我们这种情况,setOffscreenPageLimit(int limit)是无效的。
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();
}
}
这时候就需要使用fragment的懒加载机制,在用户手动滑入“发现”页面时fragment才进行加载,节省资源。
fragment中提供一个方法 setUserVisibleHint,这个方法会在fragment对用户可见/不可见时回调,但是它并不在fragment的生命周期中,因此无法保证和生命周期方法的调用顺序。
创建一个抽象类BaseLazyFragment,然后定义几个标识位
private boolean isFirstVisible = true;
private boolean isFirstInvisible = true;
private boolean isViewCreated;
private boolean isUIVisible;
重写方法onViewCreated,并在其中进行加载操作(最终是否加载还取决于当前fragment是否可见,这将在lazyLoad中进行判断):
@Override
public void onViewCreated(View view, @Nullable Bundle savedInstanceState) {
super.onViewCreated(view, savedInstanceState);
isViewCreated = true;
lazyLoad(); // 执行懒加载,因为无法确定setUserVisibleHint和onViewCreated哪个方法先执行,因此两个方法里面都需要调用lazyLoad
}
然后重写方法:
@Override
public void setUserVisibleHint(boolean isVisibleToUser) {
super.setUserVisibleHint(isVisibleToUser);
if (isVisibleToUser) {
isUIVisible = true; //当前fragment可见
if (isFirstVisible) {
//如果是第一次可见,则进行懒加载
isFirstVisible = false;
lazyLoad();
} else {
//不是第一次可见,则调用onUserVisible()
onUserVisible();
}
} else {
isUIVisible = false;
if (isFirstInvisible) {
isFirstInvisible = false;
//第一次不可见
onFirstUserInvisible();
} else {
//非第一次不可见
onUserInvisible();
}
}
}
添加lazyLoad方法,执行懒加载:
private void lazyLoad() {
if (isViewCreated && isUIVisible) { //需要进行双重判断,避免因为setUserVisibleHint先于onViewCreaetd调用时,出现空指针
onFirstUserVisible(); //进行初次可见时的加载
}
}
添加几个抽象方法:
protected abstract void onFirstUserVisible();
protected abstract void onUserVisible();
protected abstract void onFirstUserInvisible();
protected abstract void onUserInvisible();
Fragment的懒加载大概就是这样,比较简单。添加几个标识位判断是否是第一次可见/不可见、onViewCreated是否执行完(必要,否则setUserVisibleHint在onViewCreated执行完前回调,然后进行懒加载的话可能会导致空指针)。在加入懒加载之后,打开app时的内存占用能降到70m左右,下降了近20%,对于一些性能较差的用户还是比较关键的。
不过懒加载也有坏处就是用户第一次进入页面时需要短暂等待加载。因此是否需要懒加载得根据产品定位、目标人群等来决定,这就是产品经理需要考虑的问题了蛤蛤。
完整的BaseLazyFragment代码如下:
import android.os.Bundle;
import android.support.annotation.Nullable;
import android.support.v4.app.Fragment;
import android.util.Log;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
public abstract class BaseLazyFragment extends Fragment {
private boolean isFirstVisible = true;
private boolean isFirstInvisible = true;
private boolean isViewCreated;
private boolean isUIVisible;
@Nullable
@Override
public View onCreateView(LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) {
Log.i("LazyLoad", getClass().getName() + "onCreateView");
if (getLayoutId() != 0) {
return inflater.inflate(getLayoutId(), container, false);
} else {
return super.onCreateView(inflater, container, savedInstanceState);
}
}
@Override
public void onViewCreated(View view, @Nullable Bundle savedInstanceState) {
super.onViewCreated(view, savedInstanceState);
isViewCreated = true;
lazyLoad(); // 执行懒加载,因为无法确定setUserVisibleHint和onViewCreated哪个方法先执行,因此两个方法里面都需要调用lazyLoad
}
@Override
public void setUserVisibleHint(boolean isVisibleToUser) {
super.setUserVisibleHint(isVisibleToUser);
if (isVisibleToUser) {
isUIVisible = true; //当前fragment可见
if (isFirstVisible) {
//如果是第一次可见,则进行懒加载
isFirstVisible = false;
lazyLoad();
} else {
//不是第一次可见,则调用onUserVisible()
onUserVisible();
}
} else {
isUIVisible = false;
if (isFirstInvisible) {
isFirstInvisible = false;
//第一次不可见
onFirstUserInvisible();
} else {
//非第一次不可见
onUserInvisible();
}
}
}
private void lazyLoad() {
if (isViewCreated && isUIVisible) { //需要进行双重判断,避免因为setUserVisibleHint先于onViewCreaetd调用时,出现空指针
initViewsAndEvents();
onFirstUserVisible(); //进行初次可见时的加载
}
}
protected abstract int getLayoutId();
protected abstract void initViewsAndEvents();
protected abstract void onFirstUserVisible();
protected abstract void onUserVisible();
protected abstract void onFirstUserInvisible();
protected abstract void onUserInvisible();
}

535

被折叠的 条评论
为什么被折叠?



