在线观看不卡亚洲电影_亚洲妓女99综合网_91青青青亚洲娱乐在线观看_日韩无码高清综合久久

鍍金池/ 教程/ Android/ Handler 使用中可能引發(fā)的內(nèi)存泄漏
多分辨率適配常用目錄
Android 開發(fā)環(huán)境(Eclipse+ADT+Android 5.0)
Android 原型設(shè)計(jì)工具探索
Makefile 快速入門
Android Studio的NDK開發(fā)
人臉檢測-靜態(tài)
getprop 與 dumpsys 命令
Maven 編譯開源二維碼掃描項(xiàng)目 zxing
畫布 Canvas
組合控件
Linux 下的模擬器硬件加速
讀取 Excel
android.hardware.camera2 使用指南
橫豎屏切換
Ubuntu 下切換 JDK 版本
拍照和錄像 with Camera
文本與布局
按鈕控制 ViewPager 的左右翻頁
用 TableLayout 偽裝表格顯示數(shù)據(jù)
Preference Activity 使用詳解
模擬器如何重啟?試試 Genymotion!
獲得屏幕物理尺寸、密度及分辨率
語音識別
了解 native activity
Android Studio 導(dǎo)入第三方類庫、jar 包和 so 庫
啟動另一個(gè) App/apk 中的 Activity
APK 簽名
兩個(gè)開源的圖表/報(bào)表控件
android studio 導(dǎo)出 jar 包(Module)并獲得手機(jī)信息
圖片的 Base64 編解碼
混淆與反編譯
Android Studio 和 Gradle
Android 5.1 SDK 下載與配置
persistableMode 與 Activity 的持久化
adb 取出安裝在手機(jī)中的 apk
Android Studio 中的源代碼管理
Handler 使用中可能引發(fā)的內(nèi)存泄漏

Handler 使用中可能引發(fā)的內(nèi)存泄漏

目錄(?)[+]

問題描述

曾幾何時(shí),我們用原來的辦法使用 Handler 時(shí)會有下面一段溫馨的提示:

    This Handler class should be static or leaks might occur

下面是更詳細(xì)的說明(Android Studio上的警告,不知道 Eclipse 上是否相同)

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 被聲明為內(nèi)部類,那么可能導(dǎo)致它的外部類不能夠被垃圾回收。如果 Handler 是在其他線程(我們通常成為 worker thread)使用 Looper 或 MessageQueue(消息隊(duì)列),而不是 main 線程(UI 線程),那么就沒有這個(gè)問題。如果 Handler 使用 Looper 或 MessageQueue 在主線程(main thread),你需要對 Handler 的聲明做如下修改:

聲明 Handler 為 static 類;在外部類中實(shí)例化一個(gè)外部類的 WeakReference(弱引用)并且在 Handler 初始化時(shí)傳入這個(gè)對象給你的 Handler;將所有引用的外部類成員使用 WeakReference 對象。

解決方案一

上面的描述中基本上把推薦的修改方法明確表達(dá)了出來,下面的代碼是我自己使用中的一個(gè)實(shí)現(xiàn),請參考:

    private CopyFileHandler mHandler;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_appstart);
        mHandler = new CopyFileHandler(this);
        startCopyDBThread();
    }

    private void startCopyFileThread(){
        Log.d(TAG, "startCopyDBThread");
        new Thread(new Runnable() {
            @Override
            public void run() {
                //DO SOMETHING LIKE: copyDBFile();
                Message msg=mHandler.obtainMessage();
                mHandler.sendMessage(msg);
            }
        }).start();
    }

    private static class CopyFileHandler extends Handler {
        WeakReference<AppStartActivity> mActivity;
        public CopyFileHandler(AppStartActivity activity)   {
            mActivity = new WeakReference<>(activity);
        }

        public void handleMessage(Message msg) {
            final AppStartActivity activity = mActivity.get();
            //handle you message here!
        }
    }

為什么會內(nèi)存泄漏

那么為什么不這樣做會引發(fā)內(nèi)存泄漏呢?

這與幾個(gè)關(guān)鍵詞有關(guān):內(nèi)部類、Handler 的消息循環(huán)(Looper)、Java 垃圾回收機(jī)制。

需要強(qiáng)調(diào)一下,并不是每次使用 Handler 都會引發(fā)內(nèi)存泄漏,這里面有一定的幾率,需要滿足特定條件才會引起泄漏。

內(nèi)部類會有一個(gè)指向外部類的引用。

垃圾回收機(jī)制中約定,當(dāng)內(nèi)存中的一個(gè)對象的引用計(jì)數(shù)為0時(shí),將會被回收。

Handler 作為 Android 上的異步消息處理機(jī)制(好吧,我大多用來進(jìn)行 worker thread 與 UI 線程同步),它的工作是需要 Looper 和 MessageQueue 配合的。簡單的說,要維護(hù)一個(gè)循環(huán)體(Looper)處理消息隊(duì)列(MessageQueue)。每循環(huán)一次就從 MessageQueue 中取出一個(gè) Message,然后回調(diào)相應(yīng)的消息處理函數(shù)。

如果,我是說如果,循環(huán)體中有消息未處理(Message 排隊(duì)中),那么 Handler 會一直存在,那么 Handler 的外部類(通常是 Activity)的引用計(jì)數(shù)一直不會是0,所以那個(gè)外部類就不能被垃圾回收。很多人會遇到 activity 的 onDestroy 方法一直不執(zhí)行就是這個(gè)原因。

另一個(gè)解決方案的嘗試

警告描述中提到了 Handler在worker thread 中使用 Looper 或 MessageQueue,我嘗試了一下,請大家品鑒。

    private Handler testHandler;
    private Thread mThread = new Thread() {
        public void run() {
            Log.d(TAG,"mThread run");
            Looper.prepare();
            testHandler = new Handler() {
                public void handleMessage(Message msg) {
                    Log.d("TAG", "worker thread:"+Thread.currentThread().getName());
                    switch (msg.what) {
                        //handle message here
                    }
                }
            };
            Looper.loop();
        }
    };

    //start thread here
    if(Thread.State.NEW == mThread.getState()) {
        Log.d(TAG, "mThread name: " + mThread.getName());
        mThread.start();
    }

    //send message here
    testHandler.sendEmptyMessage(1);

參考:

http://stackoverflow.com/questions/11407943/this-handler-class-should-be-static-or-leaks-might-occur-incominghandler

http://m.blog.csdn.net/blog/wurensen/41907663

http://blog.csdn.net/lmj623565791/article/details/38377229