性能优化
- 使用更加轻量的数据结构
考虑使用Android专门的ArrayMap/SparseArray而不是HashMap等传统数据结构,SparseArray更加高效在于他们避免了对key与value的autobox自动装箱,并且避免了装箱后的解箱。 - 避免在Android里面使用Enum,使用enum比静态int省的dex大一倍。使用@Intdef
- 避免View的泄露导致Activity的泄露,2.3的Drawable4.0修复
- 复杂绘制开启硬件加速,SDK16开始属性动画可以直接开启:ViewPropertyAnimator.alpha().withLayer()
- bitmap优化1.解码格式ARGB_8888/RGB_565;2.缩放指定大小inScaled,inDensity,inTargetDensity;3.inbitmap;4.bitmappool
- 开启严格模式 Strict Mode,预防ANR
7.自定义View1.ClipRect裁剪画布,2.Canvas.quickReject查找交叉区域 - AlarmManager、JobSchedulor定时任务
9.发隐式Intent之前调用resolveActivity做检查
10.提供了NotificationCompat兼容类来帮助开发实现体验统一的Notification参考
11.使用MediaSessionCompat操作音乐的播放
限制应用的内存
为了整个Android系统的内存控制需要,Android系统为每一个应用程序都设置了一个硬性的Dalvik Heap Size最大限制阈值,这个阈值在不同的设备上会因为RAM大小不同而各有差异。如果你的应用占用内存空间已经接近这个阈值,此时再尝试分配内存的话,很容易引起OutOfMemoryError
的错误。
ActivityManager.getMemoryClass()
可以用来查询当前应用的Heap Size阈值,这个方法会返回一个整数,表明你的应用的Heap Size阈值是多少Mb(megabates)。
硬件加速

严格模式Strict Mode
UI线程被阻塞超过5秒,就会出现ANR,这太糟糕了。防止程序出现ANR是很重要的事情,那么如何找出程序里面潜在的坑,预防ANR呢?很多大部分情况下执行很快的方法,但是他们有可能存在巨大的隐患,这些隐患的爆发就很容易导致ANR。
Android提供了一个叫做Strict Mode的工具,我们可以通过手机设置里面的开发者选项,打开Strict Mode选项,如果程序存在潜在的隐患,屏幕就会闪现红色。我们也可以通过StrictMode API在代码层面做细化的跟踪,可以设置StrictMode监听那些潜在问题,出现问题时如何提醒开发者,可以对屏幕闪红色,也可以输出错误日志。下面是官方的代码示例:
public void onCreate() {
if (DEVELOPER_MODE) {
StrictMode.setThreadPolicy(new StrictMode.ThreadPolicy.Builder()
.detectDiskReads()
.detectDiskWrites()
.detectNetwork() // or .detectAll() for all detectable problems
.penaltyLog()
.build());
StrictMode.setVmPolicy(new StrictMode.VmPolicy.Builder()
.detectLeakedSqlLiteObjects()
.detectLeakedClosableObjects()
.penaltyLog()
.penaltyDeath()
.build());
}
super.onCreate();
}
自定义View
Android系统有提供超过70多种标准的View,例如TextView,ImageView,Button等等。在某些时候,这些标准的View无法满足我们的需要,那么就需要我们自己来实现一个View,这节会介绍如何优化自定义View的性能。
通常来说,针对自定义View,我们可能犯下面三个错误:
- 我们知道调用View.invalidate()会触发View的重绘,有两个原则需要遵守,第1个是仅仅在View的内容发生改变的时候才去触发invalidate方法,第2个是尽量使用ClipRect等方法来提高绘制的性能。
- 减少绘制时不必要的绘制元素,对于那些不可见的元素,我们需要尽量避免重绘。
- 对于不在屏幕上的元素,可以使用Canvas.quickReject把他们给剔除,避免浪费CPU资源。另外尽量使用GPU来进行UI的渲染,这样能够极大的提高程序的整体表现性能。
最后请时刻牢记,尽量提高View的绘制性能,这样才能保证界面的刷新帧率尽量的高。更多关于这部分的内容,可以看这里
Bitmap图片相关
1.解码格式
所以为了避免加载一张超大的图片,需要尽量减少这张图片所占用的内存大小,Android为图片提供了4种解码格式,他们分别占用的内存大小如下图所示:

随着解码占用内存大小的降低,清晰度也会有损失。我们需要针对不同的应用场景做不同的处理,大图和小图可以采用不同的解码率。在Android里面可以通过下面的代码来设置解码率:

2.图片缩放:
对bitmap做缩放,这也是Android里面最遇到的问题。对bitmap做缩放的意义很明显,提示显示性能,避免分配不必要的内存。Android提供了现成的bitmap缩放的API,叫做createScaledBitmap(),使用这个方法可以获取到一张经过缩放的图片。

上面的方法能够快速的得到一张经过缩放的图片,可是这个方法能够执行的前提是,原图片需要事先加载到内存中,如果原图片过大,很可能导致OOM。下面介绍其他几种缩放图片的方式。
inSampleSize能够等比的缩放显示图片,同时还避免了需要先把原图加载进内存的缺点。我们会使用类似像下面一样的方法来缩放bitmap:


重要另外,我们还可以使用inScaled,inDensity,inTargetDensity
的属性来对解码图片做处理,源码如下图所示:

还有一个经常使用到的技巧是inJustDecodeBounds,使用这个属性去尝试解码图片,可以事先获取到图片的大小而不至于占用什么内存。如下图所示:

隐式Intent之前调用resolveActivity做检查参考
Intent intent = new Intent(Intent.ACTION_XXX);
ComponentName componentName = intent.resolveActivity(getPackageManager());
if(componentName != null) {
String className = componentName.getClassName();
}
Notification兼容性问
为了解决Android系统版本差异导致的Notification兼容性问题,Android官方提供了NotificationCompat兼容类来帮助开发实现体验统一的Notification。通常来说,建立一个Notification至少会有三种元素:图标,标题,文本。我们通常会使用如下的代码来实现一个基础的Notification功能: