Skip to content

Android应用优化 网络优化 、内存优化、图片优化

Mr.wu edited this page Nov 13, 2017 · 6 revisions

网络优化

为什么?

现在App几乎都需要联网操作,做好网络优化一方面可以提高体验,另一方面可以减少流量和电量的损耗.另外,无论是对用户还是网络服务提供者,网络同样是一种资源,任何开发者都不应该假设网络资源是无限制的.

如何检测?

1、使用Android Studio里的Network Traffic Tools来查看网络请求
2、使用Android Studio中的Monitor
3、使用Fidder或者Charles等抓包工具分析网络数据包
4、如何优化?

有必要的时候务必做好缓存,无论是图片还是普通的数据,使用LruCache和DiskLruCache构建自己的缓存系统,并根据实际场景设计缓存策略
避免过度的网络同步,合并相关的网络请求
根据实际场景确定请求策略,避免使用固定的间隔频率来进行网络操作.比如连接WiFi并充电的情况下请求频率可以高,第一次网络请求失败后可以使用双倍的时间间隔来进行下一次
减少数据传输量,对传输的数据做压缩.如果传输的是图片,需要选择合适的图片格式以及根据显示大小请求合适规格的图片.对于普通数据,可以考虑使用ProtocalBuffers来减小传输数据的大小.
###某些情况下可以采用IP直连,一方面可以减少DNS解析时间,另一方面可以防止域名劫持

youhua

内存优化

为什么?

资源总是有限的,内存同样也是一种资源.在Android当中,过度的/不恰当占用内存资源,会导致应用频繁被杀死,最终也会影响用户的整体体验.任何一名开发者,都应该将节省内存牢记心中.

如何检测?

1、使用LeakCanary
2、使用MAT分析Java堆
3、使用Android Device Monitor中的Application Tracker追踪内存分配信息
4、Android Studio中的Android Monitor,选择其中的Memory
5、如何优化?

主动的释放内存,在onLowMemory()和onTrimMemory()中适当的释放内存

避免内存泄漏和内存溢出

在使用Bitmap的时候,考虑对其进行压缩,使用缓存或者改变颜色模式,比如android默认的颜色格式是ARGB_8888,在要求不高的情况下可以采用
RGB_565,这样每个像素占用的内存就可懂4byte到2byte.

###减少帧动画的使用,如果需要,通过SurfaceView实现

使用更轻量级的数据结构,比如ArrayMap/SparseArray

合理的使用相关组件,比如Service和Webview,在不需要的时候主动结束其生命周期

合理的使用多进程,比如像音乐播放器类,可以分为主进程和播放进程

使用异步队列时考虑有界队列

如果你能明确知道HashMap的大小,那就再初始化时为其制定容量

Android SDK中包含一个“zipalign”的工具,它能够对打包的应用程序进行优化。在你的应用程序上运行zipalign,使得在运行时Android与应用程序间的交互更加有效率。因此,这种方式能够让应用程序和整个系统运行得更快。

为了能够手动对齐程序包,Android 1.6及以后的SDK的tools/文件夹下都有zipalign工具。你可以使用它来对齐任何版本下的程序包。你必须在签名apk文件后进行,使用以下命令:zipalign -v 4 source.apk destination.apk
验证对齐:
以下的命令用于检查程序包是否进行了对齐:zipalign -c -v 4 application.apk

图片优化

1 主动释放ImageView的图片资源
由于我们在实际开发中,很多情况是在xml布局文件中设置ImageView的src或者在代码中调用ImageView.setImageResource/setImageURI/setImageDrawable等方法设置图像,下面代码可以回收这个ImageView所对应的资源:

private static void recycleImageViewBitMap(ImageView imageView) {
    if (imageView != null) {
        BitmapDrawable bd = (BitmapDrawable) imageView.getDrawable();
        rceycleBitmapDrawable(bd);
    }
}
private static void rceycleBitmapDrawable(BitmapDrawable bitmapDrawable) {
    if (bitmapDrawable != null) {
        Bitmap bitmap = bitmapDrawable.getBitmap();
        rceycleBitmap(bitmap);
    }
    bitmapDrawable = null;
}
private static void rceycleBitmap(Bitmap bitmap) {
    if (bitmap != null && !bitmap.isRecycled()) {
        bitmap.recycle();
        bitmap = null;
    }
}

2主动释放ImageView的背景资源
如果你的ImageView是有Background,那么下面的代码可以释放他:

public static void recycleBackgroundBitMap(ImageView view) {
    if (view != null) {
        BitmapDrawable bd = (BitmapDrawable) view.getBackground();
        rceycleBitmapDrawable(bd);
    }
}
public static void recycleImageViewBitMap(ImageView imageView) {
    if (imageView != null) {
        BitmapDrawable bd = (BitmapDrawable) imageView.getDrawable();
        rceycleBitmapDrawable(bd);
    }
}
private static void rceycleBitmapDrawable(BitmapDrawable bitmapDrawable) {
    if (bitmapDrawable != null) {
        Bitmap bitmap = bitmapDrawable.getBitmap();
        rceycleBitmap(bitmap);
    }
    bitmapDrawable = null;
}

使用zipalign优化你的apk

在编写完所有代码,并通过编译系统生成APK之后,你需要使用zipalign对APK进行重新校准。如果你不做这个步骤,会导致你的APK需要更多的RAM,因为一些类似图片资源的东西不能被mapped。

Notes::Google Play不接受没有经过zipalign的APK。

使用组件和多进程的方式

如果合适的话,有一个更高级的技术可以帮助你的app管理内存使用:通过把你的app组件切分成多个组件,运行在不同的进程中。这个技术必须谨慎使用,大多数app都不应该运行在多个进程中。因为如果使用不当,它会显著增加内存的使用,而不是减少。当你的app需要在后台运行与前台一样的大量的任务的时候,可以考虑使用这个技术。

一个典型的例子是创建一个可以长时间后台播放的Music Player。如果整个app运行在一个进程中,当后台播放的时候,前台的那些UI资源也没有办法得到释放。类似这样的app可以切分成2个进程:一个用来操作UI,另外一个用来后台的Service.

你可以通过在manifest文件中声明'android:process'属性来实现某个组件运行在另外一个进程的操作。

<service android:name=".PlaybackService"         android:process=":background" />

App启动阶段为避免在主线程创建线程池的资源消耗)使用的话务必加上优先级的设置。

Process.setThreadPriority(Process.THREAD_PRIORITY_BACKGROUND);

getByteCount()与getAllocationByteCount()的区别

一般情况下两者是相等的; 通过复用Bitmap来解码图片,如果被复用的Bitmap的内存比待分配内存的Bitmap大,那么getByteCount()表示新解码图片占用内存的大小(并非实际内存大小,实际大小是复用的那个Bitmap的大小),getAllocationByteCount()表示被复用Bitmap真实占用的内存大小(即mBuffer的长度)

BitmapFactory.decodeFile()与BitmapFactory.decodeResource()的区别

两者的调用链基本一致,但是少了默认设置density和inTargetDensity(与缩放比例相关)的步骤,也就没有了缩放比例这一说。

除了加载本地资源文件的解码方法会默认使用资源所处文件夹对应密度和手机系统密度进行缩放之外,别的解码方法默认都不会。此时Bitmap默认占用的内存 = width * height * 一个像素所占的内存。

Bitmap.compress()

质量压缩:它是在保持像素的前提下改变图片的位深及透明度等,来达到压缩图片的目的,不会减少图片的像素。进过它压缩的图片文件大小会变小,但是解码成bitmap后占得内存是不变的。

内存压缩:BitmapFactory.Options.inSampleSize

解码图片时,设置BitmapFactory.Options类的inJustDecodeBounds属性为true,可以在Bitmap不被加载到内存的前提下,获取Bitmap的原始宽高。而设置BitmapFactory.Options的inSampleSize属性可以真实的压缩Bitmap占用的内存,加载更小内存的Bitmap。

设置inSampleSize之后,Bitmap的宽、高都会缩小inSampleSize倍。例如:一张宽高为2048x1536的图片,设置inSampleSize为4之后,实际加载到内存中的图片宽高是512x384。占有的内存就是0.75M而不是12M,足足节省了15倍。

参考:

http://androidperformance.com/2015/07/20/Android-Performance-Memory-AndroidResource.html

https://juejin.im/post/58c3b29761ff4b005d906730

Home

Android 开发录

-深入理解LayoutInflater.inflate()的参数

计算机网络原理

数据库

Java 垃圾回收机制

Java 开发录

面试

搭建翻墙shadowsocks 教程

其他

Clone this wiki locally