目录
1、新建一个 Module,写主界面 MainActivity,布局 activity_main
一、前言
上篇文章我们介绍了:非静态的内部类错误使用_情形二,在Activity中,使用单例工厂类引用 Activity内部类。详细可参考博文:原创 android内存泄露:2、非静态的内部类错误使用_情形二 ,这篇文章我们将介绍:Handler的错误使用导致内存泄露
二、Handler的错误使用导致内存泄露
案例:写一个计时器
1、新建一个 Module,写主界面 MainActivity,布局 activity_main
MainActivity
public class MainActivity extends AppCompatActivity {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
}
public void handlerUse(View view) {
startActivity(new Intent(MainActivity.this, HandlerActivity.class));
}
}
activity_main
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical"
tools:context=".MainActivity">
<Button
android:text="Handler的错误使用"
android:onClick="handlerUse"
android:layout_width="wrap_content"
android:layout_height="wrap_content" />
</LinearLayout>
2、写业务逻辑
HandlerActivity
public class HandlerActivity extends AppCompatActivity {
private TextView mTextView;
private Handler mHandler = new Handler();
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_handler);
mTextView = (TextView) findViewById(R.id.tv_time);
//1秒之后执行一次以下方法
mHandler.postDelayed(new Runnable() {
@Override
public void run() {
//获取当前时间设置为View
String time = getStringTime();
mTextView.setText(time);
//这里的this代表这实现了Runnable接口的匿名内部类对象
//使得其每隔1秒都会执行该方法
mHandler.postDelayed(this, 1000);
}
}, 1000);
}
/**
* 获取系统时间并格式化
* @return
*/
private String getStringTime() {
SimpleDateFormat simpleDateFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
return simpleDateFormat.format(new Date());
}
}
3、效果展示
类似上两篇文章,使用 LeakCanary工具,会测试到内存泄露的相关信息,这里就不截图和录视频了。
4、解决方案
/**
* 我们使用Handler发送了循环任务,即:在一个任务执行完前再发送一个同样的任务。这样任务就永远也执行不完。
*
* 我们使用Handler发送了Runnable任务,该Runnable任务是一个匿名内部类,对外部类有隐式的强引用,
* 也就是Runnable对象引用到了Activity,同时Runnable被发送到了MessageQueue中,也就是MessageQueue引用到了Runnable,
* MessageQueue属于Looper对象的成员变量,因此MessageQueue又被Looper对象引用到,
* Looper对象是在Looper.prepare()阶段创建并绑定到主线程的
*/
解决方式:当 HandlerActivity销毁的时候,移除当前 mHandler发送的所有的msg消息和任务
@Override
protected void onDestroy() {
super.onDestroy();
//移除当前 mHandler发送的所有的msg消息和任务
mHandler.removeCallbacksAndMessages(null);
}