内存泄漏优化---Handler引发内存泄漏

问题描述

我们使用Handler的时候经常会有下面的提示:

This Handler class should be static or leaks might occur

打开more:

Since this Handler is declared as an inner class, it may prevent the outer class from being garbage collected. If the Handler is using a Looper or MessageQueue for a thread other than the main thread, then there is no issue. If the Handler is using the Looper or MessageQueue of the main thread, you need to fix your Handler declaration, as follows: Declare the Handler as a static class; In the outer class, instantiate a WeakReference to the outer class and pass this object to your Handler when you instantiate the Handler; Make all references to members of the outer class using the WeakReference object.

大概意思就是:

一旦Handler被声明为内部类,那么可能导致它的外部类不能够被垃圾回收。如果Handler是在其他线程(我们通常成为worker thread)使用Looper或MessageQueue(消息队列),而不是main线程(UI线程),那么就没有这个问题。如果Handler使用Looper或MessageQueue在主线程(main thread),你需要对Handler的声明做如下修改:
声明Handler为static类;在外部类中实例化一个外部类的WeakReference(弱引用)并且在Handler初始化时传入这个对象给你的Handler;将所有引用的外部类成员使用WeakReference对象。

方案一

根据提示我们的方案是写一个继承Handler的内部类,在内部类的的构造方法中让Handler持有Activity的弱引用对象,代码如下:

/**
 * Created by lizhenya.
 */
public class SplashActivity extends Activity {

    private SkipHandler handler = new SkipHandler(SplashActivity.this);

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        requestWindowFeature(Window.FEATURE_NO_TITLE);
        setContentView(R.layout.layout_activity_splash);

        isFirstRun();
    }

    /**
     * 方法描述:检测该应用是否是第一次运行
     */
    private void isFirstRun() {
        //检测是否是第一次运行该APP
        boolean isFirstRun = getSharedPreferences("FIRST_RUN", Context.MODE_PRIVATE).getBoolean("isFirstRun", true);

        if (isFirstRun) {
            handler.sendEmptyMessageDelayed(0, 1000);
        } else {
            handler.sendEmptyMessageDelayed(1, 2000);
        }
    }


    /**
     * 类描述:防止Handler造成Activity的内存泄漏
     */
    private static class SkipHandler extends Handler {
        WeakReference<Activity> mWeakActivity;

        /**
         * 方法描述:构造方法,Handler持有SplashActivity的弱引用对象
         * @param activity
         */
        public SkipHandler(Activity activity) {

            mWeakActivity = new WeakReference<Activity>(activity);
        }

        @Override
        public void handleMessage(Message msg) {
            super.handleMessage(msg);
            if (null != mWeakActivity) {
                SplashActivity mActivity = (SplashActivity) mWeakActivity.get();
                switch (msg.what) {
                    case 0:
                        this.skipOtherActivity(mActivity, WelcomeActivity.class);
                        break;
                    case 1:
                        this.skipOtherActivity(mActivity, HomeActivity.class);
                        break;
                }
            }
        }

        /**
         * 方法描述:跳转到不同的Activity
         *
         * @param activity
         * @param cls
         */
        private void skipOtherActivity(Activity activity, Class<? extends Activity> cls) {
            Intent intent = new Intent(activity, cls);
            activity.startActivity(intent);
            activity.finish();
        }
    }
}


方案二

我们分析一下,有时候我们开启线程下载东西然后用Handler去更新UI,但是我们科恩个遇到这种情况:打开Activity然后又立即把Activity销毁,但此刻也许我们的工作线程然在执行下载的好事操作,而此刻Activity有执行destroy方法,但Handler一直持有Activity的对象从而导致Activity内存的泄漏。

我们的解决方案可以是在Activity执行Destroy方法时停止工作线程,清空MessageQueue中所有的消息。

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值