上一篇从图片加载和布局方面分析怎样优化内存,这样可以解决大部分的 OOM 问题了,但是为了尽可能小的占用内存,我们还需要从其他方面入手,不光是从编程角度,还需要在业务方面配合.
在首页、搜索等页面中需要使用 ViewPager 承载不同 Fragment,并且有的需要 ViewPager 嵌套 ViewPager,如果进入 Activity 就加载 Fragment 会消耗大量资源,如网络请求、内存、布局绘制耗时耗内存,对用户而言需要等待造成不好的体验.所以需要使用懒加载方式以减少网络请求、布局绘制等不必要的消耗.
懒加载的思路就是首次Fragment加载进Activity不可见的时候不初始化布局和请求网络,让Fragment切换为可见时,再加载布局、请求网络,这样就避免首次打开Activity卡顿和消耗不必要内存.在 Fragment 重写setUserVisibleHint(boolean isVisibleToUser)
方法便可以获取到,Fragment 是否用户可见.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95
| public abstract class LazyFrgment extends Fragment {
private boolean isPrepared;
private boolean isVisible;
private boolean hasNotLazyLoad;
public void setHasNotLazyLoad(boolean hasNotLazyLoad) { this.hasNotLazyLoad = hasNotLazyLoad; }
@Nullable @Override public View onCreateView(@NonNull LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) { isPrepared = true; return inflater.inflate(getContentView(), container, false); }
@Override public void onViewCreated(@NonNull View view, @Nullable Bundle savedInstanceState) { super.onViewCreated(view, savedInstanceState); initView(view); }
@Override public void onActivityCreated(@Nullable Bundle savedInstanceState) { super.onActivityCreated(savedInstanceState); if (hasNotLazyLoad) { initData(); loadData(); } }
@Override public void setUserVisibleHint(boolean isVisibleToUser) { super.setUserVisibleHint(isVisibleToUser); isVisible = getUserVisibleHint(); if (isVisible) { onVisible(); } else { onInvisible(); } }
protected void onVisible() { lazyLoad(); }
protected void onInvisible() {
}
protected void lazyLoad() { if (isVisible && isPrepared && !hasNotLazyLoad) { isPrepared = false; initData(); loadData(); } }
protected abstract int getContentView();
protected abstract void initView(View view);
protected abstract void initData();
protected abstract void loadData();
}
|
这样当继承 LazyFragment 后,只需实现四个抽象方法后,就可以完成懒加载.这样的方式也有助于减少网络并发导致 Token 失效的问题.当 ViewPager 中 Fragment 个数过多时,对内存也会造成很大压力,所以需要用setOffscreenPageLimit
给 ViewPager 设置一个合适的 limit 值,当 ViewPager 加载 Fragment 超过这个值时,会回收栈底的 Fragment 缓解内存压力.
页面递归调用限制
当进入商品详情页后又可以进入店铺详情页,店铺详情页就可以进入商品详情页,这样的递归调用,理论情况一定会出现 OOM,就算不出现 OOM 也会让内存压力过大,有可能使应用卡顿.所以需要设置一个阈值,当页面递归调用超过这个阈值后,杀死这个阈值前所以的商品详情页.当然也可以有更复杂的规则,目前我们业务规则这样指定,但是总体思路不变.
在 API 14以后,Application 中提供了一个应用生命周期回调的注册方法,用来对应用的生命周期进行集中管理.这样可以免去手动维护 Activity 栈.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50
|
private void registerMainProcessActivityLife() { final Stack<Activity> activities = new Stack<>(); final int maxGoodDetailActivityNum = 3; registerActivityLifecycleCallbacks(new ActivityLifecycleCallbacks() { @Override public void onActivityCreated(Activity activity, Bundle savedInstanceState) { if (activity instanceof GoodsDetailActivity) { if (activities.size() >= maxGoodDetailActivityNum) { activities.peek().finish(); } activities.add(activity); } }
@Override public void onActivityStarted(Activity activity) {
}
@Override public void onActivityResumed(Activity activity) {
}
@Override public void onActivityPaused(Activity activity) {
}
@Override public void onActivityStopped(Activity activity) {
}
@Override public void onActivitySaveInstanceState(Activity activity, Bundle outState) {
}
@Override public void onActivityDestroyed(Activity activity) { activities.remove(activity); } }); }
|
复杂长页面使用 vlayout
对于电商首页而言,页面承载内容需要十分丰富,并且数量也很多,如果使用 ScrollView 根本无法满足,如果使用 RecyclerView 需要编写大量的布局,对数据结构要求很高.十分感谢阿里在的开源项目vlayout,简直是编写复杂页面之光.我们目前应用于首页、商品详情页、店铺详情页等结构样式较多,且内容较多的页面.vlayout 支持固定布局、浮动布局、浮动布局、瀑布流布局等复杂布局.vlayout 是一个针对 RecyclerView 的 LayoutManager 扩展, 主要提供一整套布局方案和布局间的组件复用的问题。通过定制化的LayoutManager,接管整个RecyclerView的布局逻辑;LayoutManager管理了一系列LayoutHelper,LayoutHelper负责具体布局逻辑实现的地方;每一个LayoutHelper负责页面某一个范围内的组件布局;不同的LayoutHelper可以做不同的布局逻辑,因此可以在一个RecyclerView页面里提供异构的布局结构,这就能比系统自带的LinearLayoutManager、GridLayoutManager等提供更加丰富的能力。同时支持扩展LayoutHelper来提供更多的布局能力.
onDestroy 置空全局变量
正常情况下,Activity finish 后系统会销毁 Activity 的实例,当该 Actiivty 对象引用没有指向原先分配给该Activity对象的内存时,该内存便成为垃圾.JVM的一个系统级线程会自动释放该内存块.但是这个有可能不及时,我们手动置空后会更加积极的回收内存.
原来并没有在意这个操作会带来多大变化,但是在优化过程发现还挺有效.