一、Bitmap内存管理与优化
-
质量压缩
-
BitmapFactory.decodeFile()
-
BitmapFactory.decodeResource()
-
BitmapFactory.decodeStream()
-
inDensity :Bitmap的像素密度
-
原理:通过算法扣掉了图片中的一些某些点附近相近的像素,达到降低质量减少文件大小的目的
BitmapFactory.Options options = new BitmapFactory.Options(); Bitmap bitmap = BitmapFactory.decodeFile(path,options); //压缩图片 降低图片的质量 视觉效应,少了一个亮级,省流量,加载到内存,能不能省内存呢? compressImageToFile(bitmap,new File(...)); public static void compressImageToFile(Bitmap bmp,File file) throws Exception{ int quality = 50;// 0 ~ 100 ByteArrayOutputStream baos = new ByteArrayOutputStream(); bmp.compress(Bitmap.CompressFormat.JPEG,quality,baos); FileOutputSteam fos = new FileOutputStream(file); fos.write(baos.toByteArray()); fos.flush(); fos.close(); }
-
注意,它只能实现对File文件的影响,对加载这个图片出来的Bitmap内存是无法节省的,因为Bitmap在内存中的大小是按照像素计算的,也就是width*height,质量压缩并不会改变Bitmap的真实像素
-
使用场景:将图片压缩后保存到本地或者将图片上传到服务器
-
-
尺寸压缩
-
原理:通过减少单位尺寸的像素值,真正意义上的降低像素
-
public static void compressBitmapToFileBySize(Bitmap bmp,File file){ int ratio = 4;//压缩尺寸的倍数,值越大,图片的尺寸就越小 Bitmap result = Bitmap.createBitmap(bmp.getWidth()/ratio,bmp.getHeight()/ratio,Bitmap.Config.ARGE_8888); Canvas canvas = new Canvas(result); RectF rect = new RectF(0,0,bmp.getWidth()/ratio,bmp.getHeight()/ratio); canvas.drawBitmap(bmp,null,rect,null); ByteArrayOutputStream baos = new ByteArrayOutputStream(); result.compress(Bitmap.CompressFormat.JPEG,100,baos); FileOutputStream fos = new FileOutputStream(file); fos.write(baos.toByteArray()); fos.flush(); fos.close(); }
-
-
采样率压缩
int inSampleSize = 8;//数值越高,图片像素越低 BitmapFactory.Options options = new BitmapFatcory.Options(); options.inJustDecodeBounds = true;//为true不会真正加载图片 options.inSampleSize = inSampleSize;//这里计算采样率 options.inJustDecodeBounds = false; Bitmap bitamp = BitampFactory.decodeFile(filePath,options);
-
IOS拍照1M的图片要比安卓拍照出来的5M图片还清楚
- 图片引擎 95年JPEG处理引擎 libjpeg.turbo 官网,用于最初的在PC上面处理图片的引擎
- 05年 skia 开发了一套skia引擎,基于JPEG的二次开发,便于浏览器的使用
- 安卓上面用的什么引擎? skia引擎,阉割版 谷歌拿了skia,去掉哈夫曼算法,采用定长编码算法
- 导致图片处理后文件变大了
- 理由:当时由于CPU和内存在手机上都非常吃紧,性能差,由于哈夫曼算法非常吃CPU
- 优化:绕过安卓Bitmap API层,自己编码
- 哈夫曼算法 用字符在文件中出现的频率表来建立一个用 0,1串表示各字符的最优表示方式
- 一个像素点包含四个信息(argb):alpha red green blue
- abcde
- a 001 b 010 c 011 d 100 e 101
- 加权信息编码
- a 80% b 10 % c 10 % d 0% e 0%
- 编码优化 a 01 b 10 c 01
- 权重(扫描图片信息,每个像素包括ARGB)
- 实现 利用libjpeg库
二、APK瘦身九道程序(代码混淆 webp svg 资源压缩 lint so库 对齐/zip)
-
SVG矢量图(常用于小图片,节省内存和空间)
-
解决问题:UI需要为同一张图片准备不同尺寸
-
创建步骤 res - new -vector asset ,然后可以选择AS自带的资源,也可以导入SVG或者PSD(不支持渐变和透明)
-
5.0以下系统兼容,app的build.gradle的defaultConfig里进行如下配置,打包时会将SVG生成相应文件夹下的png图片
vectorDrawables.generatedDensities('xhdpi','xxhdpi');
-
5.0以上系统配置
vectorDrawales.useSupportLibrary=true use: app:srcCompat="@drawable/ic_test"
-
-
Tint着色器
- tint + selector在4.4系统会Crash
- 解决问题:同一张图片需要不同颜色
-
string.xml资源配置
-
默认情况下,打包时会包含各国语言的基础方案,往往一个APP并不需要支持多国语言
//只保留简体中文和繁体字 resConfigs('zh-rCN','zh-rTN')
-
重新打包后,resources.arsc可能会减少一般体积,这些语言是在support-v7包里产生的
-
-
so库打包配置
-
移除无用的cpu架构的so库
ndk{ abiFilters('armeabi-v7a') }
-
如果APP是面向工业级,或者用户设备繁杂,比如要支持PDA,这种情况就不能这么做了
-
-
移除无用资源
- 一键移除,如果出现使用动态id使用资源会出现问题,不建议
- Refactor - Remove Unused Resources
- Analyze - Run Inspection by Name - unused resources
-
代码混淆
pass
-
资源压缩
shrinkResources true
-
开启后,发现未引用的资源会被压缩,布局代码内容消失
-
如果需要指定文件不被压缩,需要在res下raw下新建keep.xml
<?xml version="1.0" encoding="utf-8"?> <resources xmlns:tools="http://schemas.android.com/tools" tools:keep="@layout/activity_main2" tools:shrinkMode="strict" />
-
有些代码会在运行期间引用,所以需要在keep里,使其不被压缩
tools:keep="@layout/activity_main2,@layout/activity_main3"
-
-
webp
- AS里直接对文件图片右键,convert to webp ,视觉上不会有损失
-
zipalign对齐
-
资源混淆(ant/aapt/aapt2)
- 微信和美团方案,针对resources.arsc文件,编译前和编译后做处理