内存泄露的检测。
1. 在Android Studio中运行你的应用,然后切换到输出窗口的Android tab。
2. 尽情的玩耍你的应用,最好各个功能都用到,如果是Viewpager,则多滑动一些页面,观察内存的增长情况。
如果是下面这样大致平稳的曲线,就没有内存泄露。
如果是下面这样,阶梯状的曲线,基本是有内存泄露了。图片右上角显示已经分配了178.16M,一旦这个数字超过200M,程序就会崩掉。
如果得知哪些函数耗费了大量内存呢?可以记录内存的使用过程,加以分析,点击内存窗口的Start Allocation Tracking按钮开始记录,使用完再次点击停止记录。
在弹出的记录文件中可以找到使用内存较多的函数调用。这个方法浏览内存使用的情况,不能确定内存泄露的地方。
一点经验:
用FragmentStatePagerAdapter代替FragmentPagerAdapter
前者保证不再显示的页面(Off-Screen page)能够被及时删除,释放掉内存,但是bitmap内存不再此列。
减小bitmap尺寸
使用bitmap是要尽量使用小尺寸的,因为Android中一个bitmap占多大内存是由其尺寸决定的,而不是其所占硬盘空间的大小决定的。比如一个512 * 512的色彩斑斓的图片,一个1024 * 1024的黑白图片,前者所占硬盘空间更大,但是加载到Android中,后者所用内存确是前者的四倍!因为Android是按 1024 * 1024来分配内存,它不管你像素是什么样色。
使用完的bitmap要及时回收内存。
bitmap = null是一句很有用的代码。这样可以不再引用某个对象,加快垃圾回收的进程。
ImageView.setImageDrawable(null)也是脱离对之前设置的位图的引用。急速垃圾回收。
上面这两句放到Activity或者Fragment的onDestroy方法中,有奇效!
小心使用AsyncTask进行异步加载
记得在Activity或者Fragment的onDestroy方法中将AsyncTask的实例置空。否则里面引用的Bitmap内存无法释放!
如果使用ASyncTask匿名对象则可忽略此条。
FragmentPagerAdapter & FragmentStatePagerAdapter
1、如文档所述,该类内的每一个生成的 Fragment 都将保存在内存之中,因此适用于那些相对静态的页,数量也比较少的那种;如果需要处理有很多页,并且数据动态性较大、占用内存较多的情况,应该使用FragmentStatePagerAdapter。FragmentPagerAdapter 重载实现了几个必须的函数,因此来自 PagerAdapter 的函数,我们只需要实现 getCount(),即可。
2、对于页面相对较少的情况,我仍旧希望能够将生成的 Fragment 保存在内存中,在需要显示的时候直接调用,而不要产生生成、销毁对象的额外的开销,这样效率更高。这种情况下,选择 FragmentPagerAdapter 是更适合。
FragmentPagerAdapter 的使用方法:
分别重载 getItem() 以及 instantiateItem() 对象。
getItem() 只用于生成新的与数据无关的 Fragment;而 instantiateItem() 函数则先调用父类中的 instantiateItem() 取得所对应的 Fragment 对象,然后,根据对应的数据,调用该对象对应的方法进行数据设置。
@Override
public Fragment getItem(int position) {
MyFragment f = new MyFragment();
return f;
}
@Override
public Object instantiateItem(ViewGroup container, int position) {
MyFragment f = (MyFragment) super.instantiateItem(container, position);
String title = mList.get(position);
f.setTitle(title);
return f;
}
@Override
public int getItemPosition(Object object) {
return PagerAdapter.POSITION_NONE;
}