一、什么是Handler
Handler通过发送和处理Message和Runnable对象来关联相对应线程的MessageQueue。
- 可以让对应的Message和Runnable在未来的某个时间点进行相应处理。(就是在子线程耗时操作完成后,可以通知主线程更新UI)。
- 让自己想要处理的耗时操作放在子线程,让更新UI的操作放在主线程。
二、Handler的使用方法
2.1 post(runnable)
- 在成员变量中创建Handler(该Handler自动绑定到了主线程)
- 创建Runnable
- post(runnable), 在Runnable中更新UI
public class HandlerWithRunnableActivity extends AppCompatActivity implements View.OnClickListener {
private TextView statusTextView;
private Handler mHandler = new Handler();
private static final String TAG = "HandlerWithRunnableA---";
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
statusTextView = findViewById(R.id.statusTextView);
findViewById(R.id.btnDownload).setOnClickListener(this);
Log.d(TAG, "Main thread id = " + Thread.currentThread().getId());
}
@Override
public void onClick(View v) {
DownloadThread downloadThread = new DownloadThread();
downloadThread.start();
}
class DownloadThread extends Thread {
@Override
public void run() {
try {
Log.d(TAG, "DownloadThread id = " + Thread.currentThread().getId());
Log.d(TAG, "开始下载文件");
Thread.sleep(5000);
Log.d(TAG, "文件下载完成");
Runnable runnable = new Runnable() {
@Override
public void run() {
Log.d(TAG, "Runnable thread id = " + Thread.currentThread().getId());
HandlerWithRunnableActivity.this.statusTextView.setText("文件下载完成");
}
};
mHandler.post(runnable);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}
2.2 sendMessage(message)
- 在主线程中创建Handler,复写了它的handlerMessage方法
- 在子线程中通过 Message 属性调用HandlerMessage方法,来将子线程中的消息传到主线程,
- 通过handlerMessage的复写方法进行相应的UI线程的处理
public class HandlerWithMessageActivity extends AppCompatActivity implements View.OnClickListener {
private TextView statusTextView;
private Handler mHandler = new Handler() {
@Override
public void handleMessage(@NonNull Message msg) {
switch (msg.what) {
case 1:
Log.d(TAG, "Runnable thread id = " + Thread.currentThread().getId());
HandlerWithMessageActivity.this.statusTextView.setText("文件下载OK");
break;
}
}
};;
private static final String TAG = "HandlerWithMessA---";
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
statusTextView = findViewById(R.id.statusTextView);
findViewById(R.id.btnDownload).setOnClickListener(this);
Log.d(TAG, "Main thread id = " + Thread.currentThread().getId());
}
@Override
public void onClick(View v) {
DownloadThread downloadThread = new DownloadThread();
downloadThread.start();
}
class DownloadThread extends Thread {
@Override
public void run() {
try {
Log.d(TAG, "DownloadThread id = " + Thread.currentThread().getId());
Log.d(TAG, "开始下载文件");
Thread.sleep(5000);
Log.d(TAG, "文件下载完成");
Message msg = new Message();
msg.what = 1;
mHandler.sendMessage(msg);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}
三、handler机制的原理
Handler由4部分组成
- Handler
- Message
- MessageQueue
- Looper
- Looper中有一个mQueue消息队列
- MessageQueue有一个mMessages消息
- Message有一个Handler对象
- Handler有mQueue和mLooper对象
四、handler引起的内存泄漏以及解决方法
原因:非静态内部类持有外部类的匿名引用,导致外部的activity无法释放
解决办法:
- handler内部持有外部的activity的弱引用,
- 并把handler改为静态内部类,用static修饰
- 在activity中的destroy方法中调用mHandler.removeCallback()
private static class SafeHandler extends Handler {
private WeakReference<HandlerActivity> ref;
public SafeHandler(HandlerActivity activity) {
this.ref = new WeakReference(activity);
}
@Override
public void handleMessage(final Message msg) {
HandlerActivity activity = ref.get();
if (activity != null) {
activity.handleMessage(msg);
}
}
}
并且再在 Activity.onDestroy() 前移除消息,加一层保障
@Override
protected void onDestroy() {
safeHandler.removeCallbacksAndMessages(null);
super.onDestroy();
}
这样双重保障,就能完全避免内存泄露了。
注意:单纯的在 onDestroy 移除消息并不保险,因为 onDestroy 并不一定执行。