我们使用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的弱引用对象,代码如下:

    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中所有的消息。