Android消息机制介绍
Android的消息机制主要是指Handler的运行机制, Handler需要底层的MessageQueue, 和 Looper 的支撑.
-
MessageQueue
: 消息队列, 它的内部可以存储一组消息,并且提供了添加和删除小的接口.虽然名为消息队列但是内部并不是一个队列,而是一个单链表. -
Looper
: 中文翻译为循环, 由于MessageQueue
只能保存消息并不能处理消息, Looper就是用来出来处理消息的. Looper会以无限循环的方式去查询MessageQueue中是否有消息.如果有消息就直接处理,否则就一直等待.
注意一 :ThreadLocal
可以在每一个线程中存储数据, 它可以在多个个线程中互不干扰得存储并提供数据. 通过ThreadLocal 可以轻松的获取每个线程的Looper.
注意二 : 新创建的线程默认是没有Looper的.如果需要关联Handler就必须为当期那线程创建Looper.
注意三 : 主线程(UI线程), 他就是ActivityThread, ActivityThread创建的时候就会初始化Looper.因此在主线程中可以直接使用Handler.
为什么要引入消息机制(Handler)
Handler的作用实质上就是将一个任务切换到指定的线程中去执行 . Android提供这一功能主要基于以下几点 :
- Android规定智能在主线程中更新UI,如果在子线程中更新UI程序便会崩溃.
ViewRootImpl
类中的checkThread()
方法进行了这个工作.源码如下 :
// 检查是否是在主线程中更新UI
void checkThread() {
if (mThread != Thread.currentThread()) {
throw new CalledFromWrongThreadException(
"Only the original thread that created a view hierarchy can touch its views.");
}
}
- Android 不建议在主线程中进行耗时操作, 否则会引发 ANR .
基于以上两点我们就需要在子线程中进行耗时任务,比如:联网获取数据等,然后再跳转到UI线程中更新UI.
- 其实Android不允许在子线程中更新UI的一个重要原因是Android的UI控件是线程不安全的.如果多个线程同时操作UI会造成不可预知的后果 .
- Android采用锁机制来保证UI控件的线程安全有有两个原因 :
2.1 上锁会让UI访问的逻辑变的复杂.
2.2 上锁会降低UI的访问效率.
ThreadLocal 类
ThreadLocal 类是一个线程内的数据存储类. 通过他可以在指定的线程存储数据, 存储以后只能在指定的线程中才可以获取到存储的数据,对于其他线程则无法获取到数据.
测试实例
/**
* 定义一个Boolean类型的的ThreadLocal.
*/
private ThreadLocal<Boolean> mThreadLocal = new ThreadLocal<>();
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
// 1. 在主线程中设置为True
mThreadLocal.set(true);
Log.d(TAG, "MainThread : " + mThreadLocal.get());
// 2. 在线程一种进行操作
new Thread(new Runnable() {
@Override
public void run() {
mThreadLocal.set(false);
Log.d(TAG, "Thread-1 : " + mThreadLocal.get());
}
}).start();
// 3. 在线程2中操作
new Thread(new Runnable() {
@Override
public void run() {
Log.d(TAG, "Thread-2 : " + mThreadLocal.get());
}
}).start();
}
// 输出
// D/MainActivity: MainThread : true
// D/MainActivity: Thread-1 : false
// D/MainActivity: Thread-2 : null
从上面的例子中可以看出,在不同线程中设置同一个ThreadLoacal但是结果不一样.这就实现了线程范围内的数据约束.
-
set()
方法源码
public void set(T value) {
// 获取当前线程
Thread t = Thread.currentThread();
// 获取该线程中的ThreadLocalMap
ThreadLocalMap map = getMap(t);
if (map != null)
// 如果已经有了则直接保存
map.set(this, value);
else
createMap(t, value);// 创建当前线程的ThreadLocalMap对象
}
-
get()
方法源码
public T get() {
Thread t = Thread.currentThread();
ThreadLocalMap map = getMap(t);
if (map != null) {
ThreadLocalMap.Entry e = map.getEntry(this);
if (e != null)
return (T)e.value;
}
// 创建当前线程的ThreadLocal并且,设置初始值,默认是null.
return setInitialValue();
}
从ThreadLocal的set和get方法可以看出, 他们操作的对象都是当前线程绑定的那个ThreadLocal副本, 因此在不同的线程中访问同一个ThreadLocal的get和set方法,它们都是在操作当前线程中的ThreadLocal副本.
MessageQueue的工作原理
消息队列在Android中主要是指 MessageQueue
,主要操作如下:
-
enqueueMessage()
: 往消息队列中插入一条消息.就是单链表的插入操作
-
next()
从消息队列中取出一条消息并将它从消息队列删除.next()
方法是一个死循环,如果消息队列中没有消息则next() 方法会一直阻塞在这, 当有消息到来时, next() 方法就会返回这条消息将消息从单链表中删除.
具体实现而已参照源码
Looper的工作原理
Looper 会不停的从MessageQueue中查询是否有消息, 如果有消息就会立即处理,否则就会一直阻塞在那.
Looper构造方法
private Looper(boolean quitAllowed) {
mQueue = new MessageQueue(quitAllowed);
mThread = Thread.currentThread();
}
创建和启动Looper
new Thread(new Runnable() {
@Override
public void run() {
// 1. 创建Looper
Looper.prepare();
// 2. 操作
Handler handler = new Handler();
// 3. 开启Looper, 此方法会阻塞.
Looper.loop();
}
}).start();
退出Looper
Looper提供了两个退出方法:
-
quit
: 直接退出Looper.
-
quitSafely
: 设置退出标志,一旦消息处理完则退出.
Looper 的 loop()
方法
public static void loop() {
// 获取当前Looper
final Looper me = myLooper();
if (me == null) {
throw new RuntimeException("No Looper; Looper.prepare() wasn't called on this thread.");
}
// 获取当前Looper的MessageQueue
final MessageQueue queue = me.mQueue;
// Make sure the identity of this thread is that of the local process,
// and keep track of what that identity token actually is.
Binder.clearCallingIdentity();
final long ident = Binder.clearCallingIdentity();
// 循环处理消息
for (;;) {
// 调用Message的next() 方法,该方法是一个阻塞方法.
Message msg = queue.next(); // might block
if (msg == null) {
// 当MessageQueue退出时会返回null.
// No message indicates that the message queue is quitting.
return;
}
// This must be in a local variable, in case a UI event sets the logger
final Printer logging = me.mLogging;
if (logging != null) {
logging.println(">>>>> Dispatching to " + msg.target + " " +
msg.callback + ": " + msg.what);
}
final long traceTag = me.mTraceTag;
if (traceTag != 0) {
Trace.traceBegin(traceTag, msg.target.getTraceName(msg));
}
try {
// msg.target : 是指定的Handler 对象.
// dispatchMessage : 方法会到指定的线程中执行.讲逻辑切换到指定的线程中.
msg.target.dispatchMessage(msg);
} finally {
if (traceTag != 0) {
Trace.traceEnd(traceTag);
}
}
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的工作原理
Handler的工作主要包含消息的发送和接收过程, 消息的发送可以通过postXXX和sendXXX方法, 其实postXXX 是通过 sendXXX 的一系列方法来实现的.
postXXX 是通过sendXXX 实现的,源码如下
public final boolean post(Runnable r)
{
return sendMessageDelayed(getPostMessage(r), 0);
}
public final boolean postAtTime(Runnable r, long uptimeMillis)
{
return sendMessageAtTime(getPostMessage(r), uptimeMillis);
}
分析Handler消息发送部分的源码
public final boolean sendMessage(Message msg)
{
// 调用sendDelayed
return sendMessageDelayed(msg, 0);
}
public final boolean sendMessageDelayed(Message msg, long delayMillis)
{
if (delayMillis < 0) {
delayMillis = 0;
}
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);
}
通过源码我们可以最终是调用了MessageQueue的enqueueMessage()
也就是网消息队列中插入一个消息.
通过前面对Looper的loop()方法的分析我们知道最终会调用Handler的dispatchMessage
,分析下源码
/**
* Handle system messages here.
*/
public void dispatchMessage(Message msg) {
// 1. 判断msg 是否提供回调方法
if (msg.callback != null) {
handleCallback(msg);
} else {
// 2. 判断Handler是否有回调
if (mCallback != null) {
if (mCallback.handleMessage(msg)) {
return;
}
}
// 3. 执行Handler的handleMessage
handleMessage(msg);
}
}
- 首先会检查Message的
callback
是否为null.
如果不为null , 就通过handleCallback
来处理消息. Message的callback是一个Runnable对象,在Message中定义如下 :
Runnable callback;
handleCallback源码
private static void handleCallback(Message message) {
// 调用run() 方法.
message.callback.run();
}
- 其次检查mCallBack是否为null,通过mCallBack的
handleMessage(msg)
来处理消息,CallBack是一个接口定义如下 :
public interface Callback {
public boolean handleMessage(Message msg);
}
通过CallBack
可以通过如下方式创建Handler对象, Handler handler = new Handler(callback);
- 最后通过Handler的
handleMessage(msg)
方法处理消息.
主线程的消息循环
Android的主线程就是ActivityThread, 主线程的入口方法是main
如下.
public static void main(String[] args) {
Trace.traceBegin(Trace.TRACE_TAG_ACTIVITY_MANAGER, "ActivityThreadMain");
SamplingProfilerIntegration.start();
// CloseGuard defaults to true and can be quite spammy. We
// disable it here, but selectively enable it later (via
// StrictMode) on debug builds, but using DropBox, not logs.
CloseGuard.setEnabled(false);
Environment.initForCurrentUser();
// Set the reporter for event logging in libcore
EventLogger.setReporter(new EventLoggingReporter());
// Make sure TrustedCertificateStore looks in the right place for CA certificates
final File configDir = Environment.getUserConfigDirectory(UserHandle.myUserId());
TrustedCertificateStore.setDefaultUserDirectory(configDir);
Process.setArgV0("<pre-initialized>");
// 创建主线程的Looper
Looper.prepareMainLooper();
ActivityThread thread = new ActivityThread();
thread.attach(false);
if (sMainThreadHandler == null) {
sMainThreadHandler = thread.getHandler();
}
if (false) {
Looper.myLooper().setMessageLogging(new
LogPrinter(Log.DEBUG, "ActivityThread"));
}
// End of event ActivityThreadMain.
Trace.traceEnd(Trace.TRACE_TAG_ACTIVITY_MANAGER);
// 启动主线程的Looper.
Looper.loop();
throw new RuntimeException("Main thread loop unexpectedly exited");
}
- 通过源码发现有进行如下两步操作
- 调用
Looper.prepareMainLooper();
创建主运行循环. - 调动
Looper.loop();
开启消息循环.
- 调用
在ActivityThread中的Handler就是ActivityThread.H
在H中定义了很多消息.主要包括了四大组件的停止和运行等.
private class H extends Handler {
public static final int LAUNCH_ACTIVITY = 100;
public static final int PAUSE_ACTIVITY = 101;
public static final int PAUSE_ACTIVITY_FINISHING= 102;
public static final int STOP_ACTIVITY_SHOW = 103;
public static final int STOP_ACTIVITY_HIDE = 104;
public static final int SHOW_WINDOW = 105;
public static final int HIDE_WINDOW = 106;
public static final int RESUME_ACTIVITY = 107;
public static final int SEND_RESULT = 108;
public static final int DESTROY_ACTIVITY = 109;
public static final int BIND_APPLICATION = 110;
public static final int EXIT_APPLICATION = 111;
public static final int NEW_INTENT = 112;
public static final int RECEIVER = 113;
public static final int CREATE_SERVICE = 114;
public static final int SERVICE_ARGS = 115;
public static final int STOP_SERVICE = 116;
public static final int CONFIGURATION_CHANGED = 118;
public static final int CLEAN_UP_CONTEXT = 119;
public static final int GC_WHEN_IDLE = 120;
public static final int BIND_SERVICE = 121;
public static final int UNBIND_SERVICE = 122;
public static final int DUMP_SERVICE = 123;
public static final int LOW_MEMORY = 124;
public static final int ACTIVITY_CONFIGURATION_CHANGED = 125;
public static final int RELAUNCH_ACTIVITY = 126;
public static final int PROFILER_CONTROL = 127;
public static final int CREATE_BACKUP_AGENT = 128;
public static final int DESTROY_BACKUP_AGENT = 129;
public static final int SUICIDE = 130;
public static final int REMOVE_PROVIDER = 131;
public static final int ENABLE_JIT = 132;
public static final int DISPATCH_PACKAGE_BROADCAST = 133;
public static final int SCHEDULE_CRASH = 134;
public static final int DUMP_HEAP = 135;
public static final int DUMP_ACTIVITY = 136;
public static final int SLEEPING = 137;
public static final int SET_CORE_SETTINGS = 138;
public static final int UPDATE_PACKAGE_COMPATIBILITY_INFO = 139;
public static final int TRIM_MEMORY = 140;
public static final int DUMP_PROVIDER = 141;
public static final int UNSTABLE_PROVIDER_DIED = 142;
public static final int REQUEST_ASSIST_CONTEXT_EXTRAS = 143;
public static final int TRANSLUCENT_CONVERSION_COMPLETE = 144;
public static final int INSTALL_PROVIDER = 145;
public static final int ON_NEW_ACTIVITY_OPTIONS = 146;
public static final int CANCEL_VISIBLE_BEHIND = 147;
public static final int BACKGROUND_VISIBLE_BEHIND_CHANGED = 148;
public static final int ENTER_ANIMATION_COMPLETE = 149;
public static final int START_BINDER_TRACKING = 150;
public static final int STOP_BINDER_TRACKING_AND_DUMP = 151;
public static final int MULTI_WINDOW_MODE_CHANGED = 152;
public static final int PICTURE_IN_PICTURE_MODE_CHANGED = 153;
public static final int LOCAL_VOICE_INTERACTION_STARTED = 154;
}
ActivityThread通过ApplicationThread和AMS进行进程间通信, AMS以进程间通信的方式完成ActivityThread的请求后回调ApplicationThread的Binder方法, 然后ApplicationThread会想H发送消息,将逻辑从ApplicationThread切换到ActivityThread中.这就是主线程的消息循环类型