1.使用service的风险
当应用程序使用service执行后台操作时,一定要保证只用执行操作时才让service运行,操作完成时,service应当停止运行,为防止内存泄露,谷歌官方推荐使用IntentService。
2.当界面不可见的时候,释放内存
到用户打开另一个app时,上一个app已经处于不可见状态,我们应到把与界面有关的资源进行释放,只需要在Activity中,重写onTrimMemory()方法,然后在这个方法
中见监听TRIM_MEMORY_UI_HIDDEN这个级别,一旦触发之后可以进行一些操作:
@Override
public void onTrimMemory(int level) {
super.onTrimMemory(level);
if (level == TRIM_MEMORY_UI_HIDDEN){
//TODO Somethings
}
}
3.当内存紧张时释放内存
onTrimMemory()方法[整个程序不可见时,触发]方法有很多回调类型的函数,我们可以根据回调中传入的API级别,去处理资源:
TRIM_MEMORY_BACKGROUND 表示程序正常运行,不会被杀掉,但内存有点低,系统可能已经根据LruCache规则去杀进程
TRIM_MEMORY_MODERATE 表示程序运行正常,内存已经很低了,我们应该释放一些不必要的内存,否则会影响程序性能
TRIM_MEMORY_RUNNING_CRITICAL 表示程序运行正常,但系统已经开始根据lruCache规则杀掉大部分缓存进程,我们应当去释放不必要的资源
4.避免在Bitmap上浪费内存
这个前面说过,不懂的可以去看看前面博客的Bitmap加载大图优化和LruCache和DiskLruCache双缓存机制
5.使用优化过的数据集合
Android API中提供了一些优化过的数据集合工具类:SparseArray、SparseBooleanArray、LongSparseArray。可以让程序更加高效
举个例子,普通hashMap以整型为key存放数据:
这里共存放个5组数据,以整型为键值:
HashMap<Integer,String> map = new HashMap<>();
map.put(1,"value");
map.put(2,"value");
map.put(3,"value");
map.put(4,"value");
map.put(5,"value");
上面的HashMap在内存中开辟的空间是这样的:可以看出它存放数据时,开辟了63个空间只用了5个,绝大部分都浪费掉了
会造成内存的浪费
接下来看一下优化过的SparseArray,可以看到,他是根据使用到的数据个数进行开辟空间一共只用18个,大大节省内存开支
优化过的集合
SparseArray<String> //已将key作为整形
SparseArray<String> array = new SparseArray<>();
array.put(1,"value");
array.put(2,"value");
array.put(3,"value");
array.put(4,"value");
array.put(5,"value");
6.了解内存的开支状况
1>使用枚举通常会比使用静态常量要消耗两倍以上内存
2>任何一个Java类,包括内部类、匿名类都要占用500字节的内存空间
3>任何一个类的实例都要消耗12-16字节的内存开支,频繁new对象也会影响性能
4>使用HashMap时,即使只设置了一个基本数据类型的键,e.g int,但也会按照对象的大小来分配内存,大概是32字节,因此,像上面一样
5>多用优化过的数据集合
7.反抽象编程概念
面向对象的编程,会编写很多额外的代码,即使这些代码执行不到,也会映射到内存中,不仅占用更多的内存,在执行效率方面
会有所降低,所以不要滥用抽象编程
8.避免使用依赖注入框架
使用依赖注入框架后会在初始化的过程中,历经较长的初始化的过程,用不到的注解对象也会加载到内存中,可能很久
之后才会得到释放
9.使用ProGuard混淆代码
ProGuard除了混淆代码之外,还具有压缩优化代码的功能,可以删除一些无用的代码,并对类、字段、方法
重命名,重命名之后,变得更加简短,更加节省内存
Proguard的路径在SDK目录下的tools中-----------studiosdk/tools/proguard
然后修改app的build下的buildTypes的minifyEnabled值为true,就可以混淆代码
buildTypes {
release {
minifyEnabled true
proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
}
}
10.使用多个线程
想使用多个线程很简单,只需在AndroidManifest.xml文件中的应用程序组件
中声明一个android:process属性即可
比如:我想让遍历文件夹的一个Service可以运行在一个单独的线程中:
<Service android:name = "FolderService" android:process = ":background">
</Service>