讲解本技术点之前需要准备的技术点回顾
队列数据结构
Java中的ThreadLocal
Java并发编程:深入剖析ThreadLocal - 海子 - 博客园
Java中的回调方法
一个经典例子让你彻彻底底理解java回调机制 - CSDN博客
一.为什么要学习Handler机制
试想一下你在UI线程做数据库操作或者网络请求,数据量小的时候可能没什么感觉,假如很耗时长达几秒,那岂不是你的应用程序都跟死机了一样?
那有什么好的办法解决这个问题吗,没错Android系统就为我们量身定制了Handler这种消息机制
二.Handler机制原理
我估计大多数人刚开始跟我一样当时感觉看懂了,后来又忘记了,其实我觉得这就是你对技术点并没有真正的理解
Android消息机制中的4大重要角色
Handler:主要用于发送消息与处理消息
Looper:主要用于连接MessageQueue与Handler
Message:一个抽象的消息封装
MessageQueue:消息队列用于以单向链表的方式存储Message
最常用的使用场景
首先我得知道Android系统默认会执行主线程默认创建Looper并开启Looper循环
public static void main(String[] args) {
...
Looper.prepareMainLooper();
...
Looper.loop();
throw new RuntimeException("Main thread loop unexpectedly exited");
}
public static void prepareMainLooper() {
prepare(false);//调用如下
synchronized (Looper.class) {
if (sMainLooper != null) {
throw new IllegalStateException("The main Looper has already been prepared.");
}
sMainLooper = myLooper();
}
}
private static void prepare(boolean quitAllowed) {
if (sThreadLocal.get() != null) {
throw new RuntimeException("Only one Looper may be created per thread");
}
sThreadLocal.set(new Looper(quitAllowed));//这里就是我们真正初始化Looper的地方
}
public static void loop() {
...
for (;;) { //这里相当于While(true)死循环
//从MessageQueue阻塞队列中获取消息
//如果你还是不理解阻塞队列可以了解一下Java中的阻塞队列
Message msg = queue.next();
...
msg.target.dispatchMessage(msg);//(由自身发送的消息的Handler处理)
...
}
总结分析:Android系统默认执行
1.利用ThreadLocal赋值Looper对象,方便之后在同一个线程中使用这个Looper
2.开启死循环一直查询MessageQueue中是否有消息处理
public class MainActivity extends Activity {
private static final int VALUE0=0x01;
private Handler handler=new Handler(){
@Override
public void handleMessage(Message msg) {
switch (msg.what){
case VALUE0:
break;
}
}
};
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
Message message=handler.obtainMessage();
message.what=VALUE0;
handler.sendMessage(message);
}
然后来分析一下
Handler的默认构造函数
public Handler(Callback callback, boolean async) {
if (FIND_POTENTIAL_LEAKS) {
final Class klass = getClass();
if ((klass.isAnonymousClass() || klass.isMemberClass() || klass.isLocalClass()) &&
(klass.getModifiers() & Modifier.STATIC) == 0) {
Log.w(TAG, "The following Handler class should be static or leaks might occur: " +
klass.getCanonicalName());
}
}
mLooper = Looper.myLooper();//初始化Looper
if (mLooper == null) {
throw new RuntimeException(
"Can't create handler inside thread that has not called Looper.prepare()");
}
mQueue = mLooper.mQueue;//初始化MessageQueue
mCallback = callback;
mAsynchronous = async;
}
跟一下myLooper()
public static @Nullable Looper myLooper() {
return sThreadLocal.get();//对应上面分析过的prepare()方法 从ThreadLocal中获取Looper
}
总结分析:
Handler的默认构造方法主要作用就是初始化Looper与MessageQueue
handler.sendMessage(message);
其实最终调用如下方法
public boolean sendMessageAtTime(Message msg, long uptimeMillis) {
MessageQueue queue = mQueue;
if (queue == null) {
RuntimeException e = new RuntimeException(
this + " sendMessageAtTime() called with no mQueue");
Log.w("Looper", e.getMessage(), e);
return false;
}
return enqueueMessage(queue, msg, uptimeMillis);
}
private boolean enqueueMessage(MessageQueue queue, Message msg, long uptimeMillis) {
msg.target = this;//对应上面分析过的msg.target.dispatchMessage(msg)
if (mAsynchronous) {
msg.setAsynchronous(true);
}
return queue.enqueueMessage(msg, uptimeMillis);
}
boolean enqueueMessage(Message msg, long when) {
...
for (;;) {
prev = p;
p = p.next;//从这里看出MessageQueue是以单向链表的方式存储Message
...
msg.next = p; // invariant: p == prev.next
prev.next = msg;
}
...
}
整个流程总结分析:
1.利用ThreadLocal赋值Looper对象,方便之后在同一个线程中使用这个Looper
2.开启死循环一直查询MessageQueue中是否有消息处理
3.Handler发送消息到消息队列
4.MessageQueue中查询到Handler发送的消息 由发送消息的Handler回调处理
疑问以及扩展:
1.handler.post()与handler.sendMessage()有什么不同,不知道有没有童鞋跟我有过同样的疑惑,其实都底层实现都一样
post方法如下
public final boolean post(Runnable r)
{
return sendMessageDelayed(getPostMessage(r), 0);
}
sendMessage()方法如下
public final boolean sendMessage(Message msg)
{
return sendMessageDelayed(msg, 0);
}
2.Handler能否实现子线程之间的通信 当然可以 示例如下所示
package com.example.gm_kf007.android_handler;
import android.os.Handler;
import android.os.Looper;
import android.os.Message;
import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;
import android.util.Log;
import android.view.View;
import android.widget.Button;
public class MainActivityextends AppCompatActivityimplements View.OnClickListener {
private Buttonbtn_SendA;
private Buttonbtn_SendB;
private Buttonbtn_SendMain;
private HandlerhandlerA;
private HandlerhandlerB;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
ThreadA threadA =new ThreadA();
threadA.start();
ThreadB threadB =new ThreadB();
threadB.start();
btn_SendA = (Button) findViewById(R.id.btn_SendA);
btn_SendB = (Button) findViewById(R.id.btn_SendB);
btn_SendMain = (Button) findViewById(R.id.btn_SendMain);
btn_SendA.setOnClickListener(this);
btn_SendB.setOnClickListener(this);
btn_SendMain.setOnClickListener(this);
}
@Override
public void onClick(View view) {
switch (view.getId()) {
case R.id.btn_SendA:
Message msgA =handlerA.obtainMessage();
msgA.what =0x01;
handlerA.sendMessage(msgA);
break;
case R.id.btn_SendB:
Message msgB =handlerB.obtainMessage();
msgB.what =0x01;
handlerB.sendMessage(msgB);
break;
}
}
class ThreadAextends Thread {
@Override
public void run() {
Looper.prepare();
handlerA =new Handler() {
@Override
public void handleMessage(Message msg) {
switch (msg.what) {
case 0x01:
Log.e("Test", "ThreadA收到BtnA what=0x01的消息");
break;
}
}
};
Looper.loop();
}
}
class ThreadBextends Thread {
@Override
public void run() {
Looper.prepare();
handlerB =new Handler() {
@Override
public void handleMessage(Message msg) {
switch (msg.what) {
case 0x01:
Log.e("Test", "ThreadB收到BtnB what=0x01的消息");
}
}
};
Looper.loop();
}
}
@Override
protected void onDestroy() {
handlerA.removeCallbacksAndMessages(null);
handlerB.removeCallbacksAndMessages(null);
}
}
三.Handler的内存泄漏问题
方法1.Activity退出的时候清除所有消息 最佳方法
@Override
protected void onDestroy() {
super.onDestroy();
mHandler.removeCallbacksAndMessages(null);
}
方法2.使用静态内部类以及弱引用 这种方法能处理但是不是最优
原因是当消息延迟不高的时候也会出现一小段时间内存泄漏
private final MyHandler mHandler = new MyHandler(this);
private static class MyHandler extends Handler{
//对Activity的弱引用
private final WeakReference mActivity;
public MyHandler(HandlerActivity activity){
mActivity = new WeakReference(activity);
}
@Override
public void handleMessage(Message msg) {
HandlerActivity activity = mActivity.get();
if(activity==null){
super.handleMessage(msg);
return;
}
switch (msg.what) {
case DOWNLOAD_FAILED:
Toast.makeText(activity, "下载失败", Toast.LENGTH_SHORT).show();
break;
case DOWNLOAD_SUCCESS:
Toast.makeText(activity, "下载成功", Toast.LENGTH_SHORT).show();
Bitmap bitmap = (Bitmap) msg.obj;
activity.imageView.setVisibility(View.VISIBLE);
activity.imageView.setImageBitmap(bitmap);
break;
default:
super.handleMessage(msg);
break;
}
}
}
一个Handler使用不当遇到的场景示例
开发的过程中曾经碰到一个棘手的问题,调用Activity.finish函数Acitivity没有执行生命周期的ondestory函数,后面查找半天是因为有一个handler成员,因为它有一个delay消息没有处理,调用Activity.finish,Activity不会马上destory,所以记得在Ativity finish前清理一下handle中的未处理的消息,这样Activity才会顺利的destory
本人原创,转载请注明出处