Android最佳性能实践(
2015-07-16 13:21
411 查看
1、节制性使用service,请一定要注意只有当任务正在执行的时候才应该让Service运行起来,当任务执行完之后去停止Service的时候,要小心Service停止失败导致内存泄漏的情况。
2、
那么我们如何才能知道程序界面是不是已经不可见了呢?其实很简单,只需要在Activity中重写onTrimMemory()方法,然后在这个方法中监听TRIM_MEMORY_UI_HIDDEN这个级别,一旦触发了之后就说明用户已经离开了我们的程序,那么此时就可以进行资源释放操作了,如下所示:
[java] view
plaincopy
@Override
public void onTrimMemory(int level) {
super.onTrimMemory(level);
switch (level) {
case TRIM_MEMORY_UI_HIDDEN:
// 进行资源释放操作
break;
}
}
注意onTrimMemory()方法中的TRIM_MEMORY_UI_HIDDEN回调只有当我们程序中的所有UI组件全部不可见的时候才会触发,这和onStop()方法还是有很大区别的,因为onStop()方法只是当一个Activity完全不可见的时候就会调用,比如说用户打开了我们程序中的另一个Activity。因此,我们可以在onStop()方法中去释放一些Activity相关的资源,比如说取消网络连接或者注销广播***等,但是像UI相关的资源应该一直要等到
在一个很小的ImageView上显示一张高分辨率的图片不会带来任何视觉上的好处,但却会占用我们相当多宝贵的内存。
Android API当中提供了一些优化过后的数据集合工具类,如SparseArray,SparseBooleanArray,以及LongSparseArray等,使用这些API可以让我们的程序更加高效。
我们还应当清楚我们所使用语言的内存开支和消耗情况,并且在整个软件的设计和开发当中都应该将这些信息考虑在内。可能有一些看起来无关痛痒的写法,结果却会导致很大一部分的内存开支,例如:
使用枚举通常会比使用静态常量要消耗两倍以上的内存,在Android开发当中我们应当尽可能地不使用枚举。
任何一个Java类,包括内部类、匿名类,都要占用大概500字节的内存空间。
任何一个类的实例要消耗12-16字节的内存开支,因此频繁创建实例也是会一定程序上影响内存的。
在使用HashMap时,即使你只设置了一个基本数据类型的键,比如说int,但是也会按照对象的大小来分配内存,大概是32字节,而不是4字节。因此最好的办法就是像上面所说的一样,使用优化过的数据集合。
,在Android上使用抽象会带来额外的内存开支,因为抽象的编程方法需要编写额外的代码,虽然这些代码根本执行不到,但是却也要映射到内存当中,不仅占用了更多的内存
下面我们来模拟一种Activity内存泄漏的场景,内部类相信大家都有用过,如果我们在一个类中又定义了一个非静态的内部类,那么这个内部类就会持有外部类的引用,如下所示:
[java] view
plaincopy
public class MainActivity extends ActionBarActivity {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
LeakClass leakClass = new LeakClass();
}
class LeakClass {
}
......
}
目前来看,代码还是没有问题的,因为虽然LeakClass这个内部类持有MainActivity的引用,但是只要它的存活时间不会长于MainActivity,就不会阻止MainActivity被垃圾回收器回收。那么现在我们来将代码进行如下修改:
[java] view
plaincopy
public class MainActivity extends ActionBarActivity {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
LeakClass leakClass = new LeakClass();
leakClass.start();
}
class LeakClass extends Thread {
@Override
public void run() {
while (true) {
try {
Thread.sleep(60 * 60 * 1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}
......
}
这下就有点不太一样了,我们让LeakClass继承自Thread,并且重写了run()方法,然后在MainActivity的onCreate()方法中去启动LeakClass这个线程。而LeakClass的run()方法中运行了一个死循环,也就是说这个线程永远都不会执行结束,那么LeakClass这个对象就一直不能得到释放,并且它持有的MainActivity也将无法得到释放,那么内存泄露就出现了。
现在我们可以将程序运行起来,然后不断地旋转手机让程序在横屏和竖屏之间切换,因为每切换一次Activity都会经历一个重新创建的过程,而前面创建的Activity又无法得到回收,那么长时间操作下我们的应用程序所占用的内存就会越来越高,最终出现OutOfMemoryError。
2、
当界面不可见时释放内存
那么我们如何才能知道程序界面是不是已经不可见了呢?其实很简单,只需要在Activity中重写onTrimMemory()方法,然后在这个方法中监听TRIM_MEMORY_UI_HIDDEN这个级别,一旦触发了之后就说明用户已经离开了我们的程序,那么此时就可以进行资源释放操作了,如下所示:[java] view
plaincopy
@Override
public void onTrimMemory(int level) {
super.onTrimMemory(level);
switch (level) {
case TRIM_MEMORY_UI_HIDDEN:
// 进行资源释放操作
break;
}
}
注意onTrimMemory()方法中的TRIM_MEMORY_UI_HIDDEN回调只有当我们程序中的所有UI组件全部不可见的时候才会触发,这和onStop()方法还是有很大区别的,因为onStop()方法只是当一个Activity完全不可见的时候就会调用,比如说用户打开了我们程序中的另一个Activity。因此,我们可以在onStop()方法中去释放一些Activity相关的资源,比如说取消网络连接或者注销广播***等,但是像UI相关的资源应该一直要等到
当内存紧张时释放内存
避免在Bitmap上浪费内存
在一个很小的ImageView上显示一张高分辨率的图片不会带来任何视觉上的好处,但却会占用我们相当多宝贵的内存。
使用优化过的数据集合
Android API当中提供了一些优化过后的数据集合工具类,如SparseArray,SparseBooleanArray,以及LongSparseArray等,使用这些API可以让我们的程序更加高效。
知晓内存的开支情况
我们还应当清楚我们所使用语言的内存开支和消耗情况,并且在整个软件的设计和开发当中都应该将这些信息考虑在内。可能有一些看起来无关痛痒的写法,结果却会导致很大一部分的内存开支,例如:使用枚举通常会比使用静态常量要消耗两倍以上的内存,在Android开发当中我们应当尽可能地不使用枚举。
任何一个Java类,包括内部类、匿名类,都要占用大概500字节的内存空间。
任何一个类的实例要消耗12-16字节的内存开支,因此频繁创建实例也是会一定程序上影响内存的。
在使用HashMap时,即使你只设置了一个基本数据类型的键,比如说int,但是也会按照对象的大小来分配内存,大概是32字节,而不是4字节。因此最好的办法就是像上面所说的一样,使用优化过的数据集合。
谨慎使用抽象编程
,在Android上使用抽象会带来额外的内存开支,因为抽象的编程方法需要编写额外的代码,虽然这些代码根本执行不到,但是却也要映射到内存当中,不仅占用了更多的内存
尽量避免使用依赖注入框架
下面我们来模拟一种Activity内存泄漏的场景,内部类相信大家都有用过,如果我们在一个类中又定义了一个非静态的内部类,那么这个内部类就会持有外部类的引用,如下所示:[java] view
plaincopy
public class MainActivity extends ActionBarActivity {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
LeakClass leakClass = new LeakClass();
}
class LeakClass {
}
......
}
目前来看,代码还是没有问题的,因为虽然LeakClass这个内部类持有MainActivity的引用,但是只要它的存活时间不会长于MainActivity,就不会阻止MainActivity被垃圾回收器回收。那么现在我们来将代码进行如下修改:
[java] view
plaincopy
public class MainActivity extends ActionBarActivity {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
LeakClass leakClass = new LeakClass();
leakClass.start();
}
class LeakClass extends Thread {
@Override
public void run() {
while (true) {
try {
Thread.sleep(60 * 60 * 1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}
......
}
这下就有点不太一样了,我们让LeakClass继承自Thread,并且重写了run()方法,然后在MainActivity的onCreate()方法中去启动LeakClass这个线程。而LeakClass的run()方法中运行了一个死循环,也就是说这个线程永远都不会执行结束,那么LeakClass这个对象就一直不能得到释放,并且它持有的MainActivity也将无法得到释放,那么内存泄露就出现了。
现在我们可以将程序运行起来,然后不断地旋转手机让程序在横屏和竖屏之间切换,因为每切换一次Activity都会经历一个重新创建的过程,而前面创建的Activity又无法得到回收,那么长时间操作下我们的应用程序所占用的内存就会越来越高,最终出现OutOfMemoryError。
相关文章推荐
- Android音乐播放器 -- MediaPlayer Service实现
- Android采访开发——2.通用Android基础笔试题
- Android 快速开发系列 打造万能的ListView GridView 适配器
- AndroidStdio导入codestyle&&Theme
- 以自定义布局为Item的GridView不响应事件
- Android 开源项目备忘
- android Activity初次的启动的时候播放声音
- 沉浸式状态栏(Android4.0以上)
- Android HandlerThread 源码分析
- android 为apk签名
- 【Android小技巧】android 按键如何能自动触发点击
- Android:图片中叠加文字,支持拖动改变位置
- TraceView分析android应用性能
- Android -- Annotation
- 关于支付宝4.1.x以上不能支付的异常
- Android lib与libs的区别和解决apk动态加载时异常
- Android获取窗体信息的Util方法
- Android中ActionBar以及menu的代码设置样式
- Android studio 如何引用aar
- Android使用Ant自动编译签名打包详解