一.Bitmap优化
1.Bitmap decode
jpg:有压缩特别是当色彩丰富时
png:无损压缩
webp:google近年开发的无损的情况下仍保证内存占用不会过大
Re-using Bitmaps 每产生一个bitmap会分配一个内存 创建→回收→创建→回收→......
bitmap占用大量内存,所以当bitmap使用较多之后会引起GC,频繁的GC导致内存抖动的话影响产品性能、用户体验。
目前一般采用为图片分配一个对象池(申请一块内存空间,常为一个经验值)。虚拟机给一张图片对象分配内存,当获取第二张图片时覆盖第一张的内存,
第三张图片以此类推。Coding如下:
2.Pre-scaling Bitmap
当我们需求的图片大小比原图小时,可以采用保证质量的压缩。
inSampleSize = 1 2 4 分别对应 fullsize 1/2size 1/4size
在这之前,我们需要获取原图片的宽高信息
在不加载图片的情况下:options.inJustDecodeBounds=true
inTargetDensity/inDensity的实现。
调Bitmap的decodeResourse方法,传入res,resID,option
判断宽高然后计算inSampleSize(1 / 2的n次方)
while循环的计算,取到inSampleSize返回值赋给option然后调用一次decodeResourse将option传过去。
3.Smaller Pixel Format :减小bitmap每一个像素占用内存大小而非压缩宽高。
四种像素格式:
ARGB_8888:图位数较高,储存的信息数较多,图像很逼真。占3个字节。
RGB_565:需要用大图,但不需支持透明度时。占2个字节。
ARGB_4444:需要用大图,也需要用透明度时。占2个字节。
ALPHA_8:只有透明度。一个像素占1个字节。
RGB_565和ARGB_4444,占用内存小,且在非icon下与ARGB差别不大。
只有透明度的ALPHA_8 + color tint 可以达到ARGB_8888能达到的要求,并且占用内存远小于ARGB_8888。但会耗费CPU进行计算。
指定你想要的像素格式(decode耗时操作通常不放在UI线程中进行)
4.Smaller PNG files
二.其他优化
1.Method Profiling 可以看到每个线程/方法占用时间
使用:AS中advice monitor → 选中进程(左侧)→ start Method Profiling → stop → 显示统计
2.Lint Tool 对Java 代码做静态检查:程序可用性、代码安全性、代码可用性、可优化性。
使用方式:Release Builds
Command Line 一般配合CI使用
Manually 常用,在AS中手动执行一次Lint
AS → Analyze → Inspect → code → whole → project → ok → 显示在inspection
关于配置:Editor → Inspections → 检索performance(由于多数只关注性能)
3.Android-specific Containtors
Primitive sizes Object Sizes
boolean 8bits boolean java.long.Boolean
int 32bits int java.long.Integer
float 32bits float java.long.Float
long 64bits
(Autoboxing)
integer value = 0 (Primitive int)
(integer object)
自动装箱耗费内存给程序带来负担
4.优化HashMap
当元素小,数量很多,且HashMap发生多层嵌套的时候。
5.枚举Enum
由于无法控制用户是否会输入一些非法字节,当开发者不想加入判断语句时,可以采用枚举将工作抛给编译器
android提供的工具:
三.实践:图片加载库
五个方面可以优化:高效加载大图,在非UI线程处理,缓存,内存管理,显示。
(加载原始图片大小之后改变显示大小并不会减少内存使用)
1.高效加载大图(以下代码未加括号,只起示意方法作用)
BitmapFactory.Options options = new BitmapFactory.Options( );
//获取原始属性宽高
options.inJustDecodeBounds = ture
//保存在options.outwidth和options.outHeight 这两个属性中
options.inSampleSize = 4
Bitmap bitmap = BitmapFactory.decodeResource(getResources() , R.drawable.big , options );
//创建一个方法:
private int calculateInSampleSize(BitmapFactory.Option options , int requestWidth , int requestHeight )
int originWidth = option.outWidth
int originHeight = option.outHeight
int inSampleSize = 1
//加入一个判断
if ( originWidth <requestWidth &&originHeight < requestHeight )
while (originHeight/inSampleSize > requestHeight && originWidth/inSampleSize > requestWidth)
inSampleSize *= 2
2.优化解码过程,将decode放入非UI线程。Device Monitor
(主要在十三章第三节的第二个视频,异步解码图片,略微复杂,暂时省略)
3.缓存:
磁盘缓存 :disc LruCache
内存缓存:
LruCache <String , 资源名> mBitmapLruCache
....
....
mBitmapLruCache.put( "resId:" + resId , bitmap)
private set <WeakReference<Bitmap>> mReusableBitmapSet = Collections.synchronizedSet(new HashSet<WeakReference<Bitmap>>());
然后在entrykemoved方法中
mResuableBitmapSet.add( new WeakReference <Bitmap>(oldValue));
然后在do Inbackground这个方法中回调decodeResource方法
这是需要创建一个addInBitmapOptions(mOptions)在do Inbackground中
而又需要创建一个findCandidate方法在addInBitmapOptions(mOptions)中
并且在里面实现candidateMeets方法,创建getPixelSize方法,判断图片类型返回字节数。