Handlerで発生する可能性のあるメモリの漏洩

2406 ワード

前の記事でHandlerを使う方法はこうです.
public class MainActivity extends AppCompatActivity {
private TextView mTextView;
private String new_str = "";
//   Handler,      
Handler mHandler = new Handler() {
    public void handleMessage(Message msg) {
        if (msg.what == 0) {
            /*sendMessage    UI      handler handleMessage     */
            mTextView.setText(new_str);
        }
    }
};
@Override
protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.activity_main);
    new Thread(new Runnable() {
        @Override
        public void run() {
            new_str = "sendMessage  UI";
            /*sendMessage    UI       handler(     handler)*/
            mHandler.sendEmptyMessage(0);
        }
    }).start();
}             

どのようにokを見ると、実際には潜在的な危険があり、メモリの漏洩を引き起こす可能性があります.mHandlerはHandlerの非静的匿名内部クラスのインスタンスであるため、外部クラスActivityの参照を持っています.メッセージキューはLooperスレッドでメッセージをポーリングし続けていることを知っています.では、このActivityが終了すると、メッセージキューには未処理のメッセージやメッセージが処理されているが、メッセージキューのMessageはmHandlerインスタンスの参照を持ち、mHandlerはActivityの参照を持っているため、このActivityのメモリリソースがタイムリーに回収されず、メモリ漏洩を引き起こす.ここでは弱い引用を導入する必要があります.規範的な書き方は以下の通りです.
public class MainActivity extends AppCompatActivity {
private TextView mTextView;
private String new_str = "";
//   Handler,       ,  Handler    Activity    
Handler mHandler = new MyHandler(this);
@Override
protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.activity_main);
    new Thread(new Runnable() {
        @Override
        public void run() {
            new_str = "sendMessage  UI";
            /*sendMessage    UI       handler(     handler)*/
            mHandler.sendEmptyMessage(0);
        }
    }).start();
}       
static class MyHandler extends Handler{
  WeakReference mActivityReference;
  MyHandler(Activity activity) { 
      mActivityReference= new WeakReference(activity);
 } 
@Override
public void  handleMessage(Message msg) { 
 final Activity activity = mActivityReference.get(); 
 if (activity != null) {   mTextView.setText(new_str);
   } 
  }
 }  

まとめ
Handlerによるメモリ漏洩を回避:静的内部クラスは外部クラスへの参照を保持しません.したがって,静的内部クラスを用いることで漏洩を回避できる.また、handler内部で存在する外部クラスActivityを呼び出す場合は、handler内部で弱い参照を使用して存在するActivityを指すことができます.