美文网首页
笔记(十八)——安卓优化

笔记(十八)——安卓优化

作者: 木溪bo | 来源:发表于2019-07-25 17:47 被阅读0次

——个人平时笔记,看到的同学欢迎指正错误,文中多处摘录于各大博主与书籍精华

一、优化
1.布局优化:布局优化的思路是减少布局层次、减少层级嵌套。
Android中常用的四大布局:LinearLayout、RelativeLayout、FrameLayout、TableLayout。

1.同等层次的情况下,能使用 LinearLayout 和 FrameLayout 实现的效果,不用 ReleativeLayout 。
2.布局复杂的情况,使用 LinearLyout 需要增加层次的情况下,使用 ReleativeLayout ,可以减少层次
3.更加复杂的布局,使用约束布局 ContraintLayout
4.使用 include 复用布局
5.include 配合 merge 减少层级,当根布局和内层子布局一致的话,就可以将根布局设置为merge标签。merge标签只会绘制渲染一次布局所以更省时。
6.使用 ViewStub 按需加载,加大布局控件的复用率。ViewStub标签(惰性标签) 是一个不可见的,没有尺寸, 主要用于实现 View 的延迟加载,可以避免浪费资源,减少布局的绘画,只有需要的时候才会加载。普通view控件即使设置为View.GONE,之后再Inflate到多处布局时依然会再创建一个对象而浪费资源,而使用ViewStub 只能Inflate一次,之后就会被置空。
ViewStub 应用场景:首次出现的引导页,sp判断 那么这个引导页就可以用ViewStub标签包裹

总结:LinearLayout和RelativeLayout的性能差别主要体现在onMeasure方法上,RelativeLayout始终要从竖直和水平两个方向对子View进行测量。而Linearlayout,当我们没有在子View中使用layout_weight属性时,LinearLayout只需对子View进行一次测量,否则也需要对子View进行两次测量以确定最终大小。所以如果可以,我们尽量少用layout_weight属性。在使用这两个布局之前,我们可以先进行衡量,如果需要实现的布局嵌套层次不深或者嵌套层次已经固定了,可以考虑用LinearLayout,相对的,如果某个布局嵌套层次很深,此时应该考虑使用RelativeLayout或者约束布局 ContraintLayout来减少嵌套层级,从而优化布局的性能。

2.绘制优化:尽量避免在onDraw方法内做大量的操作。比如不要创建新的局部对象,不要做耗时操作。
3.内存泄漏定义:
首先我们需要了解Java中的常见内存分配,包括静态存储区(方法区)、栈和堆等。

静态存储区: 存储的是虚拟机加载的静态变量、类信息、常量、静态方法等。该区域的内存在程序编译时已经分配完成,在程序运行的整个过程都存在,这一块区域的内存是不回收的。
栈区: 存储的是方法执行时也就是方法中的局部变量和对象引用。在执行方法时,方法体内的局部变量(包括基础数据类型和对象的引用等)都在栈上创建,在方法执行结束后,该区域局部变量所持有的内存会自动释放。栈内存分配运算内置于处理器的指令集中,效率高,但该区域的容量有限。
堆区: 又称动态分配区,通常是存储new出来的Java对象的实例与对象实例内的成员变量(基本数据类型、对象)都是在堆内存中的。(成员变量的基本类型存于堆,作为局部变量的存于栈),该部分内存在没有引用不使用时会被GC回收。

内存
public class Sample {    
    //类中定义的是成员变量
    //该实例的成员变量s1、mSample1存放在栈内存中,但是
    //成员变量mSample1的对象实例存放在 堆内存
    int s1 = 0;
    //实例化一个对象实例
    Sample mSample1 = new Sample();   
    
    // 方法中的是局部变量
    //方法中的局部变量s2、mSample2存放在 栈内存
    //局部变量变量mSample2所指向的对象实例存放在 堆内存
    public void method() {        
        int s2 = 0;
        Sample mSample2 = new Sample();
    }
}
    // 变量mSample3存于栈内存,但是变量mSample3所指向的对象实例存放在堆内存
    // 该实例的成员变量s1、mSample1也存放在堆内存中
    Sample mSample3 = new Sample();

因此,我们通常说的内存泄漏是指:在堆区不断的创建对象,在该对象已经使用结束,不会再使用该对象时,却还存在别的对象(生命周期较长)引用,使该对象无法及时被GC回收,导致堆区可使用的内存越来越少,最后导致OOM内存泄漏的产生。其实Android中的内存泄漏的原因与Java中类似:生命周期较长的对象持有生命周期较短的对象的引用。

内存泄漏优化:

1.非静态内部类默认持有外部引用容易造成oom,可使用静态内部类替换,因为静态内部类是属于整个程序的;
2.单例模式导致的内存泄漏,当单例的生命周期与application保持一致时,然而创建单例时的activity无法被及时释放;
3.对生命周期较长的引用处,把context、activity等改用长生命周期的applicationContext。使用弱引用(WeakReference) 代替 强引用 持有实例。
4.属性动画导致的,无限循环动画没有在onDestroy中终止和释放,应该调用animator.cancle()停止动画。
5.滥用Static关键字导致,被 Static 关键字修饰的成员变量的生命周期 = 应用程序的生命周期,尽量避免 Static 成员变量引用资源耗费过多的实例
6.集合类未被释放
7.使用完Bitmap没有使用recycle释放资源,释放后赋为null
8.IO流使用后要关闭
9.动态广播注册绑定调用registerRceiver后,没有解绑unRegisterRceiver,从而占用内存过大又持有Activity引用,导致GC无法回收
10.adapter没使用viewHolder复用contentView,创建对象实例过多
11.AsyncTask使用后消息未使用完,所引用的activity就急着销毁,导致AsyncTask无法回收,应该在activity的destory中cancle
12.自定义view中使用TypedArray.recycle()清空,将不用的对象返回至对象池中达到复用
13.RxJava在使用RxJava时,如果在发布了一个订阅后,由于没有及时取消,导致Activity/Fragment无法销毁,导致的内存泄露,解决方法:定义一个compositeDispose对象,然后将所有的任务开关都存放到这里面,然后在Activity或者Fragment退出的时候,及时清空释放compositeDispose
14.WebView在加载网页的时候,因为网速的加载慢问题,当Activity退出的时候, WebView还在后台执行,还持有Activity对象的引用,所以在Activity退出的时候及时释放WebView

Static 关键字修饰的成员变量导致
public class ClassName {
 // 定义1个静态变量
 private static Context mContext;
 public void ClassName (Context context){
// 引用的是Activity的context
 mContext = context; 
}
// 当Activity需销毁时,由于mContext = 静态 & 生命周期 = 应用程
序的生命周期,故 Activity无法被回收,从而出现内存泄露

}
集合类未被释放导致
// 通过 循环申请Object 对象 & 将申请的对象逐个放入到集合List
List<Object> objectList = new ArrayList<>();        
       for (int i = 0; i < 10; i++) {
            Object o = new Object();
            objectList.add(o);
            o = null;
        }
// 虽释放了集合元素引用的本身:o=null)
// 但集合List 仍然引用该对象,故垃圾回收器GC 依然不可回收该对象

内存泄漏与解决总结

工作线程Thread类属于非静态内部类 / 匿名内部类,运行时默认持有外部类的引用,当工作线程运行时,若外部类MainActivity需销毁,由于此时工作线程类实例持有外部类的引用,将使得外部类无法被垃圾回收器(GC)回收,从而造成 内存泄露。


image

4.ListView优化,使用ViewHolder,不在getView中做耗时操作,通过滑动监听来判断是否需要加载itme图标。
5.Bitmap使用采样率按控件大小来加载所需图片资源大小,在不需要时释放位图资源,图片三级缓存。
6.其他优化:避免创建过多的对象;不要过多使用枚举,枚举占用内存空间比整型大;常量使用static final修饰;尽量采用静态内部类避免内部类持有外部类引用导致的内存泄漏。
7.在数据使用上,能放栈就不放堆,能私有就不公开。
二、内存分析工具
1.内存泄漏分析工具:MAT(Eclipse Memory Analyzer),分析app内存状态
2.Memory Monitor是Android Studio自带的内存监视工具Memory Monitor使用介绍
3.TraceView可视化性能调查工具,可以分析TraceView日志
三、图片优化
1、Bitmap的加载和Cache:Android对单个应用所施加的内存限制,比如16MB或者更大(各个手机厂商决定),这导致加载Bitmap的时候很容易出现内存溢出,这时就需要用到缓存策略思想了。目前比较常用的缓存策略是LruCache和DiskLruCache,其中LruCache常被用做内存缓存,而DiskLruCache常被用做硬盘存储缓存。
Bitmap使用BitmapFactory类加载,该类提供了四个方法:decodeFile、decodeResource、decodeStream和decodeByteArray,分别用于支持从文件系统、资源、输入流以及字节数组中加载出一个Bitmap,其中decodeFile和decodeResource又间接调用了decodeStream方法。
参考:Android Bitmap详解

》压缩方式:

  • 1.采样率缩放压缩, BitmapFactory.decodeByteArray(byteArray, 0, byteArray.size, options)更改options
  • 2.质量压缩,bitmap.compress(Bitmap.CompressFormat.JPEG, 100, baos)更改100参数
  • 3.放缩法压缩使用的是通过矩阵对图片进行缩放,Bitmap.createScaledBitmap(bitmap, (bitmap.width * scale).toInt(), (bitmap.height * scale).toInt(), true)
  • 4.色彩模式压缩(RGB565)使用占用像素低的,由于图片的存储格式改变,与 ARGB_8888 相比,每个像素的占用的字节由 8 变为 4 , 所以图片占用的内存也为原来的一半
bitmap优化

图片内存公式:总内存 = 宽的像素数 × 高的像素数 × 每个像素点占用的大小
由以上公式可以知道影响内存占用大小的因素是 宽高和色彩空间
加载 一个 Bitamap 可以通过设置采样率 inSampleSize 的值控制加载得到的图片的大小,来进行缩放。
从 Drawable 目录中加载图片时,系统会根据手机 DPI 和 Drawable 目录对图片进行缩放


bitmap2.png

四、App瘦身方案
1、使用一套资源
2、开启minifyEnabled混淆代码
3、开启shrinkResources去除无用资源

在gradle使用shrinkResources去除无用资源,效果非常好
android {
buildTypes {
release {
shrinkResources true
}
}
}

4、删除无用的语言资源
5、使用jpg格式图片
6、减少.so库,保留armeabi-v7a, x86即可。如果同时包含了 armeabi,armeabi-v7a和x86,所有设备都可以运行,程序在运行的时候去加载不同平台对应的so,这是较为完美的一种解决方案,但是同时也会导致包变大。
7、能使用shape背景的尽量使用shape
Android APP终极瘦身指南
Android 关于arm64-v8a、armeabi-v7a、armeabi、x86下的so文件兼容问题
五、安卓版本适配与变化 Android5.0、6.0、7.0、8.0、9.0新特性整理

  • 4.2以下不支持@JavaScriptInterface注解
  • 5.0添加了MaterialDesign样式,BLE蓝牙在5.0以上传输大小大于20btye不做限制了
  • 6.0添加危险权限动态获取
  • 7.0app要访问uri文件和系统升级需要配置FileProvider文件
  • 8.0添加分屏功能、桌面图标可以设置自适应可以自己生成圆形背景图标等,需要注意8.0版本不可以对透明的activity设置方向,8.1开始可以
  • 9.0访问https网络需要在xml清单文件设置危险权限忽略文件,或者更改为targetSdkVersion<28
  • 10.0更改targetSdkVersion<29或者清单文件设置<application android:requestLegacyExternalStorage="true" ...> 安卓10适配方案

相关文章

  • 笔记(十八)——安卓优化

    ——个人平时笔记,看到的同学欢迎指正错误,文中多处摘录于各大博主与书籍精华 一、优化1.布局优化:布局优化的思路是...

  • 印象笔记安卓系统同步失败怎么办?

    退出安卓系统印象笔记账号,重新登录! 退出安卓系统印象笔记账号,重新登录!! 退出安卓系统印象笔记账号,重新登录!!!

  • 安卓开发——安卓性能优化

    前言 安卓程序运行在手机端,用户更加注重程序的流畅度,因此程序的流畅性是安卓程序性能的一个重要指标。程序员在编写程...

  • 安卓优化系列之安卓应用的启动

    前言 目前的安卓应用基本上都趋于成熟了,所以目前对安卓开发的要求不再是实现功能了,而是要能够优化应用。然而安卓应用...

  • 安卓性能优化

    前言 安卓程序运行在手机端,用户更加注重程序的流畅度,因此程序的流畅性是安卓程序性能的一个重要指标。程序员在编写程...

  • 安卓性能优化

    安卓性能优化到底优化哪几个方面? 布局优化 减少布局文件的层级(测量/布局/绘制的时间减少):可以使用Relati...

  • 安卓性能优化

    Overdraw(过度绘制)描述的是屏幕上的某个像素在同一帧的时间内被绘制了多次。在多层次的UI结构里面,如果不可...

  • 安卓性能优化

    Android的性能优化方法 1. 布局优化 使用 标签、标签、 控件 复杂布局...

  • 安卓布局优化

    推介使用布局 线性布局 (LinearLayout) 线性的 垂直的 水平的 相对布局(RelativeLay...

  • 安卓布局优化

    我们在XML资源文件上一顿、 等操作,就可以完成视图的布局。安卓中的view呈树状...

网友评论

      本文标题:笔记(十八)——安卓优化

      本文链接:https://www.haomeiwen.com/subject/ddpkrqtx.html