美文网首页Android技术知识Android知识Android开发
什么时候会自溢,BOY们你懂吗?

什么时候会自溢,BOY们你懂吗?

作者: 磨砺营 | 来源:发表于2016-10-14 09:27 被阅读27次

    【威哥说】感谢大家的大力支持, 昨天微信号里要爆棚了,让我惊讶不已,再次感谢大家,请受威哥一拜!提醒大家务必把邀请的名单发到美女老师的QQ里,以免漏了统计哈。活动结束后会统一公布领取视频的方式。

    【活动链接】威哥视频获取通道

    我们在开发应用的过程中,总是会出现崩溃错误,那么,这是为什么呢?由于什么导致又如何避免呢?今天,我们就来总结下Android中的内存问题!

    (一)查询数据库没有关闭游标

    (二) 构造Adapter时,没有使用缓存的 convertView

    (三) Bitmap对象不在使用时调用recycle()释放内存

    (四) 释放对象的引用

    (一) 查询数据库没有关闭游标

    【描述】

    程序中经常会进行查询数据库的操作,但是经常会有使用完毕Cursor后没有关闭的情况。如果我们的查询结果集比较小,对内存的消耗不容易被发现,只有在常时间大量操作的情况下才会复现内存问题,这样就会给以后的测试和问题排查带来困难和风险。

    【示例代码】

    Cursor cursor = getContentResolver().query(uri ...);

    if (cursor.moveToNext()) {

    ... ...

    }

    【修正示例代码】

    Cursor cursor = null;

    try {

    cursor = getContentResolver().query(uri ...);

    if (cursor != null && cursor.moveToNext()) {

    ... ...

    }

    } finally {

    if (cursor != null) {

    try {

    cursor.close();

    } catch (Exception e) {

    //ignore this

    }

    }

    }

    (二) 构造Adapter时,没有使用缓存的 convertView

    【描述】

    以构造ListView的BaseAdapter为例,在BaseAdapter中提高了方法:

    public View getView(int position, View convertView, ViewGroup parent)

    来向ListView提供每一个item所需要的view对象。初始时ListView会从BaseAdapter中根据当前的屏幕布局实例化一定数量的 view对象,同时ListView会将这些view对象缓存起来。当向上滚动ListView时,原先位于最上面的list item的view对象会被回收,然后被用来构造新出现的最下面的list item。这个构造过程就是由getView()方法完成的,getView()的第二个形参 View convertView就是被缓存起来的list item的view对象(初始化时缓存中没有view对象则convertView是null)。

    由此可以看出,如果我们不去使用convertView,而是每次都在getView()中重新实例化一个View对象的话,即浪费资源也浪费时间,也会使得内存占用越来越大。ListView回收list item的view对象的过程可以查看:android.widget.AbsListView.java --> void addScrapView(View scrap) 方法。

    【示例代码】

    public View getView(int position, View convertView, ViewGroup parent) {

    View view = new Xxx(...);

    ... ...

    return view;

    }

    【修正示例代码】

    public View getView(int position, View convertView, ViewGroup parent) {

    View view = null;

    if (convertView != null) {

    view = convertView;

    populate(view, getItem(position));

    ...

    } else {

    view = new Xxx(...);

    ...

    }

    return view;

    }

    (三) Bitmap对象不在使用时调用recycle()释放内存

    【描述】

    有时我们会手工的操作Bitmap对象,如果一个Bitmap对象比较占内存,当它不在被使用的时候,可以调用Bitmap.recycle()方法回收此对象的像素所占用的内存,但这不是必须的,视情况而定。可以看一下代码中的注释:

    /**

    * Free up the memory associated with this bitmap's pixels, and mark the

    * bitmap as "dead", meaning it will throw an exception if getPixels() or

    * setPixels() is called, and will draw nothing. This operation cannot be

    * reversed, so it should only be called if you are sure there are no

    * further uses for the bitmap. This is an advanced call, and normally need

    * not be called, since the normal GC process will free up this memory when

    * there are no more references to this bitmap.

    */

    (四) 释放对象的引用

    【描述】

    这种情况描述起来比较麻烦,举两个例子进行说明。

    【 示例A】假设有如下操作

    public class DemoActivity extends Activity {

    ... ...

    private Handler mHandler = ...

    private Object obj;

    public void operation() {

    obj = initObj();

    ...

    [Mark]

    mHandler.post(new Runnable() {

    public void run() {

    useObj(obj);

    }

    });

    }

    }

    我们有一个成员变量 obj,在operation()中我们希望能够将处理obj实例的操作post到某个线程的MessageQueue中。在以上的代码中,即便是 mHandler所在的线程使用完了obj所引用的对象,但这个对象仍然不会被垃圾回收掉,因为DemoActivity.obj还保有这个对象的引用。 所以如果在DemoActivity中不再使用这个对象了,可以在[Mark]的位置释放对象的引用,而代码可以修改为:

    ... ...

    public void operation() {

    obj = initObj();

    ...

    final Object o = obj;

    obj = null;

    mHandler.post(new Runnable() {

    public void run() {

    useObj(o);

    }

    }

    }

    【完】

    相关文章

      网友评论

        本文标题:什么时候会自溢,BOY们你懂吗?

        本文链接:https://www.haomeiwen.com/subject/hhygyttx.html