注册

分享Android开发中常见的代码优化方案

前言


首先要做相关优化,就得先要大致清晰影响性能的相关因素,这样可以做针对性调优会比较有条理。


比较常见的性能调优因素有:



  • 内存:Java 一般通过 JVM 对内存进行分配管理,主要是用 JVM 中堆内存来存储 Java 创建的对象。系统堆内存的读写速度非常快,所以基本不存在读写性能瓶颈。但由于内存成本要比磁盘高,相比磁盘,内存的存储空间又非常有限。所以当内存空间被占满,对象无法回收时,就会导致内存溢出、内存泄露等问题。
  • 异常:抛出异常需要构建异常栈,对异常进行捕获和处理,这个过程非常消耗系统性能。
  • 网络:对于传输数据比较大,或者是并发量比较大的系统,网络就很容易成为性能瓶颈。
  • CPU: 复杂的计算,会长时间,频繁地占用cpu执行资源;例如:代码递归调用,JVM频繁GC以及多线程情况下切换资源都会导致CPU资源繁忙。

对以上这些因素可以在代码中做相关优化处理。


延迟加载(懒加载)优化


了解预加载



  • ViewPager控件有预加载机制,即默认情况下当前页面左右相邻页面会被加载,以便用户滑动切换到相邻界面时,更加顺畅的显示出来
  • 通过ViewPager的setOffscreenPageLimit(int limit)可设置预加载页面数量

介绍延迟加载


等页面UI展示给用户时,再加载该页面数据(从网络、数据库等),而不是依靠ViewPager预加载机制提前加载部分,甚至更多页面数据。可提高所属Activity的初始化速度,另一方面也可以为用户节省流量.而这种延迟加载方案已经被诸多APP所采用。


相关概括



  • 没有打开页面,就不预加载数据,当页面可见时,才加载所需数据。
  • 换句话说延迟加载就是可见时才去请求数据。
  • 实际应用开发中有哪些延迟加载案例:

    • ViewPager+Fragment 搭配使用延迟加载
    • H5网页使用延迟加载



ViewPager与Fragment延迟加载的场景



  • ViewPager中setOffscreenPageLimit(int limit)部分源码
//默认的缓存页面数量(常量)
private static final int DEFAULT_OFFSCREEN_PAGES = 1;

//缓存页面数量(变量)
private int mOffscreenPageLimit = DEFAULT_OFFSCREEN_PAGES;

public void setOffscreenPageLimit(int limit) {
//当我们手动设置的limit数小于默认值1时,limit值会自动被赋值为默认值1(即DEFAULT_OFFSCREEN_PAGES)
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) {
//经过前面的拦截判断后,将limit的值设置给mOffscreenPageLimit,用于
mOffscreenPageLimit = limit;
populate();
}
}


  • 思路分析:Fragment中setUserVisibleHint(),此方法会在onCreateView()之前执行,当viewPager中fragment改变可见状态时也会调用,当fragment 从可见到不见,或者从不可见切换到可见,都会调用此方法,使用getUserVisibleHint() 可返回fragment是否可见状态。在onActivityCreated()及setUserVisibleHint()方法中都调一次lazyLoad() 方法。
public abstract class BaseMVPLazyFragment<T extends IBasePresenter> extends BaseMVPFragment<T> {
/**
* Fragment的View加载完毕的标记
*/
protected boolean isViewInitiated;
/**
* Fragment对用户可见的标记
*/
protected boolean isVisibleToUser;
/**
* 是否懒加载
*/
protected boolean isDataInitiated;

...

/**
* 第一步,改变isViewInitiated标记
* 当onViewCreated()方法执行时,表明View已经加载完毕,此时改变isViewInitiated标记为true,并调用lazyLoad()方法
*/
@Override
public void onActivityCreated(Bundle savedInstanceState) {
super.onActivityCreated(savedInstanceState);
isViewInitiated = true;
//只有Fragment onCreateView好了,
//另外这里调用一次lazyLoad()
prepareFetchData();
//lazyLoad();
}

/**
* 第二步
* 此方法会在onCreateView()之前执行
* 当viewPager中fragment改变可见状态时也会调用
* 当fragment 从可见到不见,或者从不可见切换到可见,都会调用此方法
*/
@Override
public void setUserVisibleHint(boolean isVisibleToUser) {
super.setUserVisibleHint(isVisibleToUser);
this.isVisibleToUser = isVisibleToUser;
prepareFetchData();
}

/**
* 第四步:定义抽象方法fetchData(),具体加载数据的工作,交给子类去完成
*/
public abstract void fetchData();

/**
* 第三步:在lazyLoad()方法中进行双重标记判断,通过后即可进行数据加载
* 第一种方法
* 调用懒加载,getUserVisibleHint()会返回是否可见状态
* 这是fragment实现懒加载的关键,只有fragment 可见才会调用onLazyLoad() 加载数据
*/
private void lazyLoad() {
if (getUserVisibleHint() && isViewInitiated && !isDataInitiated) {
fetchData();
isDataInitiated = true;
}
}

/**
* 第二种方法
* 调用懒加载
*/
public void prepareFetchData() {
prepareFetchData(false);
}

/**
* 第三步:在lazyLoad()方法中进行双重标记判断,通过后即可进行数据加载
*/
public void prepareFetchData(boolean forceUpdate) {
if (isVisibleToUser && isViewInitiated && (!isDataInitiated || forceUpdate)) {
fetchData();
isDataInitiated = true;
}
}
}

多线程优化: 建议使用线程池


用线程池的好处


可重用线程池中的线程,避免频繁地创建和销毁线程带来的性能消耗;有效控制线程的最大并发数量,防止线程过大导致抢占资源造成阻塞;可对线程进行有效管理



  • RxJava,RxAndroid,底层对线程池的封装管理非常值得参考。

作者:沐小琪吖
链接:https://juejin.cn/post/7246977137362108472
来源:稀土掘金
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。

0 个评论

要回复文章请先登录注册