您的位置:首页 > 移动开发 > Android开发

Handler源码原理分析

2017-11-19 23:52 141 查看
Android 系统内部是消息机制,什么意思?

说说Handler运行机制?

Handler功能定义:各线程互相通讯用的。常用子线程在做完某事之后然后去更新UI之类。当然两个子线程也能用Handler相互通讯。

本文主要分析两个线程是怎么通信的?通过源码分析原理是什么?

子与主线程通讯用法:

Handler mHandler = new Handler(){
@Override
public void handleMessage(Message msg) {
super.handleMessage(msg);
switch(msg.what){
case 100:
String s = msg.what+" arg1="+msg.arg1+" arg2="+msg.arg2+" obj="+msg.obj;
mTextView.setText(s);

Logger.d(s);
break;
default:

break;
}
}
};

....
new Thread(new Runnable() {
@Override
public void run() {
try {
Thread.sleep(3000);
mHandler.sendEmptyMessage(100);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}).start();


子与子线程通讯用法:

new Thread("thread2"){
public void run() {
Looper.prepare();
mHandler = new Handler(){
@Override
public void handleMessage(Message msg) {
super.handleMessage(msg);
String s = msg.what+" arg1="+msg.arg1+" arg2="+msg.arg2+" obj="+msg.obj;
Logger.d(s);
}
};
Looper.loop();
}
}.start();


发送时不变,还是用handler对象直接发送空消息,或者创建消息发送。

就多了
Looper.prepare()
Looper.loop();
等下会讲为什么。

需要分析的类

Message:消息对象,用到存放数据,和下一个Message对象

MessageQueue:字面意思消息队列,但其实它并不是队列,不过确实是负责消息的插入和取出

Handler:给用户层用来创建和发送消息,和处理收到的消息

Looper:不断循环取消息,和调用Handler处理消息

(说实话,这种看别人简单的总结根本不能理解,肯定想问,这到底是Handler发送处理消息,还是Looper发送处理消息?等等疑问。这都个人理解,还是看源码说吧)

先来看传递的对象Message,有几个常用属性。

**Message.class**
public int what; //区分消息的标识,在发送消息和接收时确认
public int arg1,arg2; //可以传递两个int值
public Object obj; //其它想要传递的对象


然后直接进Handler 类
mHandler.sendEmptyMessage(100);
看看发送时做了什么。

**Handler.class**
public final boolean sendMessage(Message msg){
return sendMessageDelayed(msg,0);
}
...
//延迟多少毫秒发送
public final boolean sendMessageDelayed(Message msg,long delayMillis){
if(delayMillis< 0){
delayMillis=0;
}
//        SystemClock.uptimeMillis()系统开机时间
return sendMessageAtTime(msg,SystemClock.uptimeMillis()+delayMillis);
}
//在一个准确时间发送
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;
if (mAsynchronous) {
msg.setAsynchronous(true);
}
return queue.enqueueMessage(msg, uptimeMillis);
}


可以看到,不管是
sendMessage
,还是
sendMessageDelayed
等……最后都是调用了
sendMessageAtTime
,然后
enqueueMessage
,又分发给了
queue.enqueueMessage(msg, uptimeMillis)
,然后发现有个
MessageQueue queue
,看在哪赋值?在Handler构造函数中,Handler构造函数也很多,最终进:

**Handler.class**
public Handler(Callback callback, boolean async) {
...
mLooper = Looper.myLooper();
if (mLooper == null) {
throw new RuntimeException(
"Can't create handler inside thread that has not called Looper.prepare()");
}
mQueue = mLooper.mQueue;
mCallback = callback;
mAsynchronous = async;
}


观察到mQueue是从Looper中拿来的,如果Looper为空,就
throw new RuntimeException()
,那进
Looper.myLooper();


**Looper.class**
public static @Nullable Looper myLooper() {
return sThreadLocal.get();
}


看sThreadLocal赋值

**Looper.class**
// sThreadLocal.get() will return null unless you've called prepare().
static final ThreadLocal<Looper> sThreadLocal = new ThreadLocal<Looper>();


直接在初始化就定义了,并且static final,说明一个进程只有一个,并无再赋值,然后看ThreadLocal是什么?

ThreadLocal 定义:与线程想关的数据存储类。

ThreadLocal 使用

ThreadLocal<Boolean> mThreadLocal=new ThreadLocal<>();

@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_second);

mThreadLocal.<
ef6a
span class="hljs-keyword">set(true);
Logger.d(Thread.currentThread() + " " + mThreadLocal.get());
new Thread(new Runnable() {
@Override
public void run() {
Logger.d(Thread.currentThread() + " " + mThreadLocal.get());
mThreadLocal.set(false);
Logger.d(Thread.currentThread() + " " + mThreadLocal.get());

}
}).start();
}
**log**
D/: Thread[main,5,main] true
D/: Thread[Thread-221,5,main] null
D/: Thread[Thread-221,5,main] false


用法简单。只有get、set、remove。可以看到,主线程set(true),get()是true。在子线程中,第一次get,因为没有set,直接为null。然后set(false),取出false,说明在子线程中,并没有get到主线程set的值。看看实现:

**ThreadLocal.class**
public class ThreadLocal<T> {

public T get() {
Thread currentThread = Thread.currentThread();
Values values = values(currentThread);
if (values != null) {
Object[] table = values.table;
int index = hash & values.mask;
if (this.reference == table[index]) {
return (T) table[index + 1];
}
} else {
values = initializeValues(currentThread);
}
return (T) values.getAfterMiss(this);
}
public void set(T value) {
Thread currentThread = Thread.currentThread();
Values values = values(currentThread);
if (values == null) {
values = initializeValues(currentThread);
}
values.put(this, value);
}
...
Values values(Thread current) {
return current.localValues;
}
static class Values {
private Object[] table;
}
}


Values 为ThreadLocal 的静态内部类,可以看到,数据最终存储的地方在Thread对象本身里的localValues.table数组里,ThreadLocal只是判断线程,然后把数据有序在放在table里,这里用了一个高效存储算法,table[i]为key,[i+1]为value,大概就是这样意思,这样可能效率性能会好吧!

如果Thread对象本身Values存储怎么办?实现这个和线程相关的存储数据有很多方法,自己也可以实现,下面自己实现一个:

//自己写的ThreadLocal
public class ThreadLocal<V> {

private Map<Long,V> mMap;

public ThreadLocal() {
mMap = new HashMap<>();
}

public V get(){
long id = Thread.currentThread().getId();
return mMap.get(id);
}

public void put(V value){
long id = Thread.currentThread().getId();
mMap.put(id,value);
}
}


用线程唯一标识为Key就行,效率可能没google写的ThreadLocal好。

再回到Looper.myLooper()方法。

**Looper.class**
public static @Nullable Looper myLooper() {
return sThreadLocal.get();
}


这里线程取到的肯定为空,唯一赋值方法在

public static void prepare() {
prepare(true);
}

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));
}


所以我们在子线程初始化Handler时,才要
Looper.prepare();
为了实例化Looper,而且每个线程还只能调用一次,那我们的主线程在那调用的呢?那就要到ActivityThread.class看看了,ActivityThread就是每个应用的大门,应用的main函数。activity、service、broadcasts等都是在这里启动。

public final class ActivityThread {
...
public static void main(String[] args) {
...省略代码若干
Looper.prepareMainLooper();
ActivityThread thread = new ActivityThread();
thread.attach(false);
if (sMainThreadHandler == null) {
sMainThreadHandler = thread.getHandler();
}
...
Looper.loop();

throw new RuntimeException("Main thread loop unexpectedly exited");
}

final Handler getHandler() {
return mH;
}
}


可以看到,有熟悉的java的main,
new Handler()
之前调用
Looper.prepareMainLooper();
这个内部也是
prepare()
,而且这个Handler处理这个应用系统所有Message,Activity生命周期、createService等都是这个handler进行分发。这个类以后要好好研究,所以为什么这就是android系统内部的消息机制,无论点击按钮,启动页面,都是通过Handler进行发送消息然后分发到各个类处理。

Ok,创建了Looper,创建了
MessageQueue
,然后看
MessageQueue
enqueueMessage
方法

boolean enqueueMessage(Message msg, long when) {
...
synchronized (this) {
...
msg.markInUse();
msg.when = when;
Message p = mMessages;//单链表的第一个message
boolean needWake;//是否需要唤醒,如果链表中没有待处理的message,主线程将睡眠
if (p == null || when == 0 || when < p.when) {
// New head, wake up the event queue if blocked.
msg.next = p;
mMessages = msg;
needWake = mBlocked;//上一个message为空,说明这是要处理message队列的第一个,将唤醒主线程,这里会为true
} else {
needWake = mBlocked && p.target == null && msg.isAsynchronous();
//这一段逻辑是取出链表中的最后一个Message prev,把新的msg赋值给它的next
Message prev;
for (;;) {
prev = p;
p = p.next;
if (p == null || when < p.when) {
break;
}
if (needWake && p.isAsynchronous()) {
needWake = false;
}
}
msg.next = p; // invariant: p == prev.next
prev.next = msg;
}

// We can assume mPtr != 0 because mQuitting is false.
if (needWake) {
nativeWake(mPtr);//为true,将唤醒主线程
}
}
return true;
}


这里可以看到,当前msg是赋值给最后一个msg的next,这里像是单链表。如图:



Message mMessages;即是链表第一个msg,也就是最快将要处理的msg(如果不为空的话)

这里有两种情况,else表示链表不为空,通过for循环,定位到最后一个msg,然后把新传递进来的msg赋值给最后一个msg的next。这就算是添加成功了。if表示链表为空(如果你进入一个新页面,不做任何操作,msg队列将会被处理完,然后主线程会睡眠,当有新的msg进来时,要唤醒主线程)
nativeWake(mPtr);
是个native方法,唤醒主线程。

到此,msg就算是添加到队列中了,然后在哪里处理呢?

这就要看ActivityThread中main方法最后调用了
Looper.loop();
因为这个会阻塞线程,所以要放在线程最后调用。

public static void loop() {
final Looper me = myLooper();
...
final MessageQueue queue = me.mQueue;
...
for (;;) {
Message msg = queue.next(); // might block
if (msg == null) {
return;
}
Printer logging = me.mLogging;
if (logging != null) {
logging.println(">>>>> Dispatching to " + msg.target + " " +
msg.callback + ": " + msg.what);
}

msg.target.dispatchMessage(msg);

if (logging != null) {
logging.println("<<<<< Finished to " + msg.target + " " + msg.callback);
}
...
}
}


简单理解就是循环从
MessageQueue
next();
方法取msg,为空将结束循环,否则
msg.target.dispatchMessage(msg);
这里
msg.target
就是创建msg时的handler,进

dispatchMessage
方法。

**Handler.class**
public void dispatchMessage(Message msg) {
if (msg.callback != null) {
handleCallback(msg);
} else {
if (mCallback != null) {
if (mCallback.handleMessage(msg)) {
return;
}
}
handleMessage(msg);
}
}


如果msg有
callback
,这个callback是
Runnable
,否则检查
mCallback
不为空,调用
mCallback.handleMessage(msg)
,最后调用自身的
handleMessage(msg);
,我们一般都是直接
new Handler()
,重写
handleMessage(msg)
方法。可以看见传递
callback
也是可以的。这里比较简单。

然后重点看
queue.next()
,也就是取出msg方法

**MessageQueue.class**
Message next() {
int nextPollTimeoutMillis = 0;
for (; ; ) {
...
nativePollOnce(ptr, nextPollTimeoutMillis);
...
synchronized (this) {
// Try to retrieve the next message.  Return if found.
final long now = SystemClock.uptimeMillis();
Message prevMsg = null;
Message msg = mMessages;
...
if (msg != null) {
// Got a message.
mBlocked = false;
if (prevMsg != null) {
prevMsg.next = msg.next;
} else {
mMessages = msg.next;
}
msg.next = null;
msg.markInUse();
return msg;

} else {
// No more messages.
nextPollTimeoutMillis = -1;
}
...
}
}
}


大致为
mMessages
是否为空,不为空就把
return mMessages
出去,并且
next
标记清掉,给
mMessages = msg.next;
赋于下一个msg。为空的话
nextPollTimeoutMillis = -1;
下次循环中,

nativePollOnce(ptr, nextPollTimeoutMillis);
为-1时将睡眠。

而且我们还发现
Printer logging = me.mLogging;
会调用
Printer.println(String n)
,说明我们可以监听到msg的处理,例:

if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
Looper.myLooper().setMessageLogging(new Printer(){
@Override
public void println(String x) {
Log.d("TAG",x);
}
});
Looper.myLooper().getQueue().addIdleHandler(new MessageQueue.IdleHandler() {
@Override
public boolean queueIdle() {//消息队列处理完毕回调,return false 将只能监听一次结束
return true;
}
});
}


addIdleHandler
可以监听消息队列处理完毕,
setMessageLogging
可以监听消息处理前后,打打log:

D/: >>>>> Dispatching to Handler (android.view.Choreographer$FrameHandler) {c0d260e} android.view.Choreographer$FrameDisplayEventReceiver@5a82f: 0
D/: <<<<< Finished to Handler (android.view.Choreographer$FrameHandler) {c0d260e} android.view.Choreographer$FrameDisplayEventReceiver@5a82f
D/: >>>>> Dispatching to Handler (android.view.ViewRootImpl$ViewRootHandler) {650110} android.view.View$PerformClick@c098179: 0
D/: <<<<< Finished to Handler (android.view.ViewRootImpl$ViewRootHandler) {650110} android.view.View$PerformClick@c098179
D/: >>>>> Dispatching to Handler (android.view.ViewRootImpl$ViewRootHandler) {650110} android.view.View$UnsetPressedState@c36fb1f: 0
D/: <<<<< Finished to Handler (android.view.ViewRootImpl$ViewRootHandler) {650110} android.view.View$UnsetPressedState@c36fb1f
D/: >>>>> Dispatching to Handler (android.app.ActivityThread$H) {b0be8e6} null: 101
D/: <<<<< Finished to Handler (android.app.ActivityThread$H) {b0be8e6} null
D/: >>>>> Dispatching to Handler (android.view.ViewRootImpl$ViewRootHandler) {650110} null: 6
D/: <<<<< Finished to Handler (android.view.ViewRootImpl$ViewRootHandler) {650110} null
D/: >>>>> Dispatching to Handler (android.view.Choreographer$FrameHandler) {c0d260e} android.view.Choreographer$FrameDisplayEventReceiver@5a82f: 0
D/: <<<<< Finished to Handler (android.view.Choreographer$FrameHandler) {c0d260e} android.view.Choreographer$FrameDisplayEventReceiver@5a82f
D/: >>>>> Dispatching to Handler (android.app.ActivityThread$H) {b0be8e6} null: 100


总结:

Handler
消息机制就是,主线程不断循环(
Looper.loop
)检查有无待处理msg(
queue.next
),有就处理(
handler.dispatchMessage()
),没有就睡眠(
nativePollOnce()
)。当子线程发送了一个msg时(
queue.enqueueMessage
),唤醒主线程(
nativeWake()
),主线程就接着处理(
queue.next
),从而实现了子线程与主线程通信。原理也就是子线程与主线程共同操作一个队列,一存,一取。原理简单粗暴,不过
nativePollOnce
睡眠、
nativeWake
唤醒、两个为native方法,肯定不是sleep那么简单。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息