Android 弱引用使用示例

 結合靜態內部類和WeakReference來解決Activity中可能存在的Handler內存泄露問題。

Activity中我們需要新建一個線程獲取數據,使用handler - sendMessage方式。下面是這一過程的一般性代碼:

 public class MainActivity extends Activity {

     //...
     private int page;
     private Handler handler = new Handler() {

         @Override
         public void handleMessage(Message msg) {
             if (msg.what == 1) {

                 //...

                 page++;
             } else {

                 //...

             }

         };
     };

     @Override
     protected void onCreate(Bundle savedInstanceState) {
         super.onCreate(savedInstanceState);
         setContentView(R.layout.activity_main);

         //...

         new Thread(new Runnable() {
             @Override
             public void run() {
                 //.. 
                 Message msg = Message.obtain();
                 msg.what = 1;
                 //msg.obj = xx;
                 handler.sendMessage(msg);
             }
         }).start();

         //...

     }

 }

在Eclispe中Run Link,將會看到警示信息:This Handler class should be static or leaks might occur …點擊查看此信息,其詳情中對問題進行了說明並給出了建議性的解決方案。

Issue: Ensures that Handler classes do not hold on to a reference to an outer class
Id: HandlerLeak

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定義成內部靜態類,並在此靜態內部類中定義一個WeakReference的引用,由於指示外部的Activity對象。

問題分析:

Activity具有自身的生命週期,Activity中新開啓的線程運行過程中,可能此時用戶按下了Back鍵,或系統內存不足等希望回收此Activity,由於Activity中新起的線程並不會遵循Activity本身的什麼週期,也就是說,當Activity執行了onDestroy,由於線程以及Handler 的HandleMessage的存在,使得系統本希望進行此Activity內存回收不能實現,因爲非靜態內部類中隱性的持有對外部類的引用,導致可能存在的內存泄露問題。

因此,在Activity中使用Handler時,一方面需要將其定義爲靜態內部類形式,這樣可以使其與外部類(Activity)解耦,不再持有外部類的引用,同時由於Handler中的handlerMessage一般都會多少需要訪問或修改Activity的屬性,此時,需要在Handler內部定義指向此Activity的WeakReference,使其不會影響到Activity的內存回收同時,可以在正常情況下訪問到Activity的屬性。

Google官方給出的建議寫法爲:



 public class MainActivity extends Activity {

     //...
     private int page;
     private MyHandler mMyHandler = new MyHandler(this);

     private static class MyHandler extends Handler {

         private WeakReference<MainActivity> wrActivity;

         public MyHandler(MainActivity activity) {
             this.wrActivity = new WeakReference<MainActivity>(activity);
         }

         @Override
         public void handleMessage(Message msg) {
             if (wrActivity.get() == null) {
                 return;
             }
             MainActivity mActivity = wrActivity.get();
             if (msg.what == 1) {

                 //...
                 mActivity.page++;

             } else {

                 //...

             }
         }

     }

     @Override
     protected void onCreate(Bundle savedInstanceState) {
         super.onCreate(savedInstanceState);
         setContentView(R.layout.activity_main);

         //...

         new Thread(new Runnable() {
             @Override
             public void run() {
                 //.. 
                 Message msg = Message.obtain();
                 msg.what = 1;
                 //msg.obj = xx;
                 mMyHandler.sendMessage(msg);
             }
         }).start();

         //...

     }

 }



 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章