1 內存泄漏根本原因
內存泄漏的根本原因是:長生命週期的對象持有短生命週期的對象,短生命週期的對象就無法及時釋放。
2 Handler錯誤用法
private Handler handler = new Handler() {
@Override
public void handleMessage(Message msg) {
super.handleMessage(msg);
Toast.makeText(MainActivity.this, "測試", Toast.LENGTH_SHORT).show();
}
};
Handler允許我們發送延時消息,如果在延時消息未處理完,而此時Handler所在的Activity被關閉,但因爲上述Handler用法則可能會導致內存泄漏。首先,Handler是以內部類的形式被創建,那麼它將隱性持有外部類的對象,而且,在Toast中還以MainActivity.this方式顯性持有了MainActivity的對象,那麼,在延時消息未處理完時,Handler無法釋放外部類MainActivity的對象,從而導致內存泄漏產生。
3 Handler正確用法
package com.yds.jianshu.mobile;
import android.app.Activity;
import android.os.Handler;
import android.os.Message;
import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;
import android.view.View;
import android.widget.TextView;
import android.widget.Toast;
import java.lang.ref.WeakReference;
public class MainActivity extends AppCompatActivity{
private static final String TAG = "[MainActivity]";
private MyHandler handler;
private TextView tv;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
initData();
}
private void initData(){
tv = findViewById(R.id.text);
handler = new MyHandler(this);
}
@Override
protected void onDestroy() {
super.onDestroy();
if (handler!=null){
handler.removeCallbacksAndMessages(null);
}
}
private static class MyHandler extends Handler{
private WeakReference<MainActivity>reference;
public MyHandler(MainActivity activity){
reference = new WeakReference<>(activity);
}
@Override
public void handleMessage(Message msg) {
super.handleMessage(msg);
MainActivity activity = reference.get();
if (activity!=null){
Toast.makeText(activity, "測試", Toast.LENGTH_SHORT).show();
activity.tv.setText("測試");
}
}
}
}
4 Runnable錯誤用法
private Runnable mRunnable = new Runnable() {
@Override
public void run() {
}
};
一樣的道理,該使用方式是創建了一個內部類,內部類隱性持有外部類對象的引用,如果Activity結束,Runnable裏面的任務沒有處理完,則不會釋放Activity的引用,則Activity無法被回收,造成內存泄漏。
5 Runnable正確用法
private static class MyRunnable implements Runnable{
WeakReference<MainActivity> reference;
public MyRunnable(MainActivity activity){
reference = new WeakReference<>(activity);
}
@Override
public void run() {
MainActivity activity = reference.get();
}
}
6 總結
- 如果直接new一個Handler,則Handler是一個非靜態內部類,它隱性地持有外部類的對象。如果外部類需要結束,但消息隊列中還有消息未處理完,則Handler不會釋放外部類的對象,從而造成內存泄漏。
- 如果直接new一個Runnable,Runnable也是一個非靜態內部類,它隱性地持有外部類的對象。如果外部類需要結束,但Runnable中還有任務未處理完,則Runnable不會釋放外部類的對象,從而造成內存泄漏。