1,android 消息机制主要是指Handler的运行机制
发送消息后会通过enqueueMesage 把消息发送到消息队列MessageQueue,Looper会不断的从消息队列中拿出消息,looper是一个线程,当消息队列中没有消息的时候,这个looper线程就会被挂起来。
什么是挂起呢?通俗讲就是不去做它该做的事情。比如老师讲课,学生却不听,那么就是这些学生把老师挂起来了。
2,ThreadLocal的工作原理
定义:ThreadLocal是一个线程内部的数据存储类,通过它可以在指定的线程中存储数据,数据存储以后,只能再指定线程中可以获取到存储的数据,对于其他线程来说则无法获取到数据。
Thread A和Thread B不能拿到对方线程之间的数据
ThreadLocal好比一个钱包,只有自己可以在其中取钱。
看一段代码
//创建一个本地线程,因为是在单元测试中写的代码,所以我们把它当作主线程
//ThreadLocal 需要传入一个泛型,
// ThreadLocal里面有一个内部类ThreadLocalMap,ThreadLocalMap类里有一个键值对,键值对的值就是我们传入的泛型,
//k是我们当前线程的名字,
ThreadLocal<String> threadLocal = new ThreadLocal<String>(){
//初始化的方法
@Nullable
@Override
protected String initialValue() {
//不调用父类的,我们自己重写,查看源码可以知道,它默认返回的是一个null
// return super.initialValue();
return "张欣爱我一生一世";
}
};
//打印输出"张欣爱我一生一世"
System.out.println(threadLocal.get());
我们分析下以上代码的源码
查看threadLocal.get()源码(源码a)
public T get() {
//拿到当前的线程
Thread t = Thread.currentThread();
ThreadLocalMap map = getMap(t);
if (map != null) {
ThreadLocalMap.Entry e = map.getEntry(this);
if (e != null) {
@SuppressWarnings("unchecked")
T result = (T)e.value;
return result;
}
}
return setInitialValue();
}
ThreadLocalMap getMap(Thread t) {
return t.threadLocals;
}
再看下getMap(t);(源码b)
ThreadLocalMap getMap(Thread t) {
return t.threadLocals;
}
返回的是Thread类的threadLocals。
我们再看下Thread类(源码c)
ThreadLocal.ThreadLocalMap threadLocals = null;
在Thread类中也没有对threadLocals赋值
我们返回源码a处
也就是这句代码
ThreadLocalMap map = getMap(t);
map是空,所以会执行
return setInitialValue();
我们点进去看看setInitialValue源码(源码h)
private T setInitialValue() {
//调用我们重写的initialValue();我们重写的这个方法返回的是"张欣爱我一生一世"
//这里的泛型T就是String,这里的value就是"张欣爱我一生一世"
T value = initialValue();
//获取当前线程
Thread t = Thread.currentThread();
//这里的map依旧是null
ThreadLocalMap map = getMap(t);
if (map != null)
map.set(this, value);
else
//执行这句代码
createMap(t, value);
return value;
}
我们看看createMap(t, value);代码的源码(源码i)
ThreadLocal类的该方法源码是
void createMap(Thread t, T firstValue) {
t.threadLocals = new ThreadLocalMap(this, firstValue);
}
在这里我们终于为Thread类的threadLocals赋值了。
经过源码的分析,我们终于知道为什么会返回"张欣爱我一生一世"了;
我们再看一段源码
package com.example.xiaoxijizhi;
import androidx.annotation.Nullable;
import androidx.appcompat.app.AppCompatActivity;
import android.os.Bundle;
public class MainActivity extends AppCompatActivity {
private ThreadLocal<String> threadLocal;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
//创建一个本地线程,因为是在单元测试中写的代码,所以我们把它当作主线程
//ThreadLocal 需要传入一个泛型,
// ThreadLocal里面有一个内部类ThreadLocalMap,ThreadLocalMap类里有一个键值对,键值对的值就是我们传入的泛型,
//k是我们当前线程的名字,
threadLocal = new ThreadLocal<String>(){
//初始化的方法
@Nullable
@Override
protected String initialValue() {
//不调用父类的,我们自己重写,查看源码可以知道,它默认返回的是一个null
// return super.initialValue();
return "张欣爱我一生一世";
}
};
//打印输出"张欣爱我一生一世"
System.out.println(threadLocal.get());
// 创建一个子线程
Thread thread = new Thread(new Runnable() {
@Override
public void run() {
String value = threadLocal.get();
System.out.println(value);//打印输出"张欣爱我一生一世"
threadLocal.set("我不爱张欣");
System.out.println(threadLocal.get());//打印输出"我不爱张欣"
//清理线程
threadLocal.remove();
}
});
thread.start();
}
}
我们再次查看threadLocal.get();源码(源码a)
public T get() {
//得到我们创建的子线程
Thread t = Thread.currentThread();
//这里的map依旧为null
ThreadLocalMap map = getMap(t);
if (map != null) {
ThreadLocalMap.Entry e = map.getEntry(this);
if (e != null) {
@SuppressWarnings("unchecked")
T result = (T)e.value;
return result;
}
}
//因为为空,所执行这句代码
return setInitialValue();
}
我们看下setInitialValue();源码(源码b)
private T setInitialValue() {
T value = initialValue();
Thread t = Thread.currentThread();
ThreadLocalMap map = getMap(t);
if (map != null)
map.set(this, value);
else
createMap(t, value);
return value;
}
同第一次分析的一模一样。
3,估计有人心里犯嘀咕了,第二部分讲的ThreadLocal跟消息机制有毛关系呢?看官别急,一点一点来。我们下面正式进入主题了。我们从app启动讲解。
(1) app启动的时候做的事情
我们查看ActivityThread类的main方法
public static void main(String[] args) {
Looper.prepareMainLooper();
}
我们查找Looper.prepareMainLooper();方法源码
public static void prepareMainLooper() {
115 prepare(false);
116 synchronized (Looper.class) {
117 if (sMainLooper != null) {
118 throw new IllegalStateException("The main Looper has already been prepared.");
119 }
120 sMainLooper = myLooper();
121 }
122 }
继续查看 prepare(false);的源码
private static void prepare(boolean quitAllowed) {
102 if (sThreadLocal.get() != null) {
103 throw new RuntimeException("Only one Looper may be created per thread");
104 }
105 sThreadLocal.set(new Looper(quitAllowed));
106 }
这里就有ThreadLocal对象,创建了全局唯一的主线程Looper对象
在Looper的构造方法里面创建了全局唯一的MessageQueue对象,同时把线程对象赋值为当前线程,即主线程
private Looper(boolean quitAllowed) {
268 mQueue = new MessageQueue(quitAllowed);
269 mThread = Thread.currentThread();
270 }
271
(2)activity 中创建Handler
创建Handler的时候会拿到全局唯一的Loop对象( Looper looper = Looper.myLooper() 通过该代码拿到)。拿到Looper对象是在主线程
我们看一段代码
package com.example.xiaoxijizhi;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import androidx.appcompat.app.AppCompatActivity;
import android.os.Bundle;
import android.os.Handler;
import android.os.Message;
import android.util.Log;
import android.view.View;
public class MainActivity extends AppCompatActivity {
private Handler handler = new Handler(){
@Override
public void handleMessage(@NonNull Message msg) {
super.handleMessage(msg);
//打印输出1
Log.i("zhang_xin",msg.what+"");
}
};
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
}
public void click(View view) {
new Thread(new Runnable() {
@Override
public void run() {
Message message = new Message();
message.what = 1;
handler.sendMessage(message);
}
}).start();
}
}
非常简单的一段代码,我们在源码中查看它是如何运行的。
我们从创建Handler开始,查看new Handler()源码
public Handler() {
this(null, false);
}
public Handler(@Nullable Callback callback, boolean async) {
if (FIND_POTENTIAL_LEAKS) {
final Class<? extends Handler> 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());
}
}
//在Handler创建的时候,会拿到我们全局唯一的Looper对象
mLooper = Looper.myLooper();
if (mLooper == null) {
throw new RuntimeException(
"Can't create handler inside thread " + Thread.currentThread()
+ " that has not called Looper.prepare()");
}
//从Looper对象中得到全局唯一的MessageQueue对象
mQueue = mLooper.mQueue;
mCallback = callback;
mAsynchronous = async;
}
我们在查看 mLooper = Looper.myLooper();源码
public static @Nullable Looper myLooper() {
return sThreadLocal.get();
}
从sThreadLocal中得到Looper对象。
(3)消息发送
messag.target=this 把message赋值给handler(target就是handler)
我们看下 handler.sendMessage(message);的源码
追踪源码可以发现Handler类如下代码
public boolean sendMessageAtTime(@NonNull 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);
}
我们继续追踪enqueueMessage(queue, msg, uptimeMillis);源码,依然是在Handler类
private boolean enqueueMessage(@NonNull MessageQueue queue, @NonNull Message msg,
long uptimeMillis) {
//注意这个target,是一个Handler类对象,这里把我们的Handler赋值到Message的target中
msg.target = this;
msg.workSourceUid = ThreadLocalWorkSource.getUid();
if (mAsynchronous) {
msg.setAsynchronous(true);
}
return queue.enqueueMessage(msg, uptimeMillis);
}
我们点进去msg.target,会发现他是Message类的一个成员变量,
Handler.target
我们在进入这个句代码看下 queue.enqueueMessage(msg, uptimeMillis);它的源码。源码在MessageQueue里
boolean enqueueMessage(Message msg, long when) {
if (msg.target == null) {
throw new IllegalArgumentException("Message must have a target.");
}
if (msg.isInUse()) {
throw new IllegalStateException(msg + " This message is already in use.");
}
synchronized (this) {
if (mQuitting) {
IllegalStateException e = new IllegalStateException(
msg.target + " sending message to a Handler on a dead thread");
Log.w(TAG, e.getMessage(), e);
msg.recycle();
return false;
}
msg.markInUse();
msg.when = when;
Message p = mMessages;
boolean needWake;
if (p == null || when == 0 || when < p.when) {
// New head, wake up the event queue if blocked.
msg.next = p;
//这里把我们的消息赋值给MessageQueue中的全局变量,然后把消息放到了消息对列中
mMessages = msg;
needWake = mBlocked;
} else {
// Inserted within the middle of the queue. Usually we don't have to wake
// up the event queue unless there is a barrier at the head of the queue
// and the message is the earliest asynchronous message in the queue.
needWake = mBlocked && p.target == null && msg.isAsynchronous();
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);
}
}
return true;
}
(4)消息处理
ThreadActivity类的main方法中,会有这句代码
Looper.loop()
这句代码就是开启循环,我们点进去看下。
public static void loop() {
//拿到Loop对象
final Looper me = myLooper();
if (me == null) {
throw new RuntimeException("No Looper; Looper.prepare() wasn't called on this thread.");
}
//拿到消息队列
final MessageQueue queue = me.mQueue;
for (;;) {
//不断的从消息队列中拿消息
Message msg = queue.next(); // might block
if (msg == null) {
// No message indicates that the message queue is quitting.
return;
}
//调用Handler的dispatchMessage方法
msg.target.dispatchMessage(msg);
if (observer != null) {
observer.messageDispatched(token, msg);
}
dispatchEnd = needEndTime ? SystemClock.uptimeMillis() : 0;
} catch (Exception exception) {
if (observer != null) {
observer.dispatchingThrewException(token, msg, exception);
}
throw exception;
} finally {
ThreadLocalWorkSource.restore(origWorkSource);
if (traceTag != 0) {
Trace.traceEnd(traceTag);
}
}
if (logSlowDelivery) {
if (slowDeliveryDetected) {
if ((dispatchStart - msg.when) <= 10) {
Slog.w(TAG, "Drained");
slowDeliveryDetected = false;
}
} else {
if (showSlowLog(slowDeliveryThresholdMs, msg.when, dispatchStart, "delivery",
msg)) {
// Once we write a slow delivery log, suppress until the queue drains.
slowDeliveryDetected = true;
}
}
}
if (logSlowDispatch) {
showSlowLog(slowDispatchThresholdMs, dispatchStart, dispatchEnd, "dispatch", msg);
}
if (logging != null) {
logging.println("<<<<< Finished to " + msg.target + " " + msg.callback);
}
// Make sure that during the course of dispatching the
// identity of the thread wasn't corrupted.
final long newIdent = Binder.clearCallingIdentity();
if (ident != newIdent) {
Log.wtf(TAG, "Thread identity changed from 0x"
+ Long.toHexString(ident) + " to 0x"
+ Long.toHexString(newIdent) + " while dispatching to "
+ msg.target.getClass().getName() + " "
+ msg.callback + " what=" + msg.what);
}
msg.recycleUnchecked();
}
}
我们看下Handler的dispatchMessage()做了什么
public void dispatchMessage(@NonNull Message msg) {
if (msg.callback != null) {
handleCallback(msg);
} else {
if (mCallback != null) {
if (mCallback.handleMessage(msg)) {
return;
}
}
handleMessage(msg);
}
}
这里会执行handlerMessage(msg)方法。
我们看下Handler的handlerMessage(msg)方法,会发现它是一个空方法,具体实现我们可以自己定义
public void handleMessage(@NonNull Message msg) {
}
4,消息的阻塞,唤醒,延时入队
(1)Looper 的阻塞主要是靠 MessageQueue 来实现的,在next()@MessageQuese 进行阻塞(阻塞不会卡),在 enqueueMessage()@MessageQueue 进行唤醒(有阻塞就有唤醒,阻塞和唤醒都是native方法)。主要依赖 native 层的 Looper 依靠 epoll 机制进行的。
(2)阻塞的native方法
nativePollOnce(ptr, nextPollTimeoutMillis);
这里调用naive方法操作管道,由nextPollTimeoutMillis决定是否需要阻塞
nextPollTimeoutMillis为0的时候表示不阻塞,为-1的时候表示一直阻塞直到被唤醒。
阻塞的时候native里会做一些资源的释放,所以主线程不会被卡死
(3)第一条消息延迟的发送(延迟入队),就是该消息阻塞固定时间(小于Integer.MaxValue)。
第二条消息假如不延迟发送,会把该次发送的时间与上次发送的时间做比较,如果这次消息早于上次发送的消息,就把上一条消息标记为下一条消息,把当前消息赋值为全局消息,然后唤醒。(可以理解为在Message对象池中把消息按照时间排序)
(4)Message对象池最多可以存放50message消息。
(5)