共计 13672 个字符,预计需要花费 35 分钟才能阅读完成。
「Android」Android 的音讯机制
概述
Android 的音讯机制次要指的是 Handler 机制。Handler的运行须要 MessageQueue 和Looper的撑持:
- MessageQueue:音讯队列。外部存储了一组信息,以队列的模式对外提供插入和删除的工作,外部存储构造以单链表的数据结构来存储音讯列表。
- Looper:音讯循环。MessageQueue 只是一个音讯的存储单元,不能去解决音讯,而 Looper 就填补了这个性能,Looper 会以有限循环的模式去查找是否有新音讯,如果有的话就解决音讯,否则就始终期待。
Looper 中还有一个非凡概念就是 ThreadLocal,ThreadLocal 不是线程,它的作用是在每个线程中互不烦扰的存储并提供数据。Handler 创立的时候会采纳以后线程的 Looper 来结构音讯循环系统,而此处获取以后线程 Looper 的形式就是通过 ThreadLocal。
线程默认是没有 Looper 的,如果须要应用 Handler 就必须为线程创立 Looper。主线程,也即 UI 线程 ActivityThread,被创立时会初始化 Looper,所以主线程默认能够间接应用 Handler。
Handler 的运行机制以及 Handler 所附带的 MessageQueue 和 Looper 的工作过程,实际上是一个整体。Handler 的次要作用是 将一个工作切换到某个指定的线程中去执行。
- 为什么 Android 不容许子线程拜访 UI?
答:因为 Android 的 UI 控件不是线程平安的,如果在多线程中并发拜访会导致 UI 控件处于不可预期的状态。- 为什么不对 UI 控件的拜访加锁?
答:首先,加锁会让 UI 拜访逻辑变得复杂;其次,加锁会升高 UI 拜访的效率,因为锁机制会阻塞某些线程的执行。
应用
- sendEmptyMessage()
- sendMessage()
- post()
Handler mHanlder = new Handler(Looper.getMainLooper()) {
@Override
public void handleMessage(@NonNull Message msg) {super.handleMessage(msg);
switch (msg.what) {
case 0:
Log.i(TAG, "thread 1");
case 1:
Log.i(TAG, "thread 2");
}
}
};
@Override
protected void onCreate(Bundle savedInstanceState) {super.onCreate(savedInstanceState);
setContentView(R.layout.activity_demo);
new Thread("Thread#1") {
@Override
public void run() {super.run();
// sendEmptyMessage
mHanlder.sendEmptyMessage(0);
}
}.start();
new Thread("Thread#2") {
@Override
public void run() {super.run();
Message message = Message.obtain();
message.what = 1;
message.obj = "obj";
// sendMessage
mHanlder.sendMessage(message);
}
}.start();
new Thread("Thread#3") {
@Override
public void run() {super.run();
// post
mHanlder.post(new Runnable() {
@Override
public void run() {Log.i(TAG, "thread 3");
}
});
}
}.start();}
能够通过 Handler 的 send 办法发送一个音讯,音讯会在 Looper 中解决;能够通过 Hander 的 post 办法将一个 Runnable 投递到 Looper 中解决,其实 post 也是通过 send 办法来实现的。
Handler 的 send 办法被调用时,会调用 MessageQueue 的 enqueueMessage 办法将这个音讯放入音讯队列中,而后 Looper 发现有新音讯到来时,就会解决这个音讯。最终音讯中的 Runnable 或者 Handler 的 handleMessage 办法就会被调用。Looper 是运行在 创立 Handler 所在的线程中 的,这样一来 Handler 的业务逻辑就被切换到了 创立 Handler 所在的线程中 去执行了。
ThreadLocal
ThreadLocal 是一个线程外部的数据存储类,通过它能够在指定的线程中存储数据,数据存储当前,只有在指定线程中能够获取到存储的数据,对于其余线程来说无奈获取该数据。当某些数据是以线程为作用域并且不同线程具备不同的数据正本的时候,能够思考采纳 ThreadLocal。
比方,对于 Handler 来说,须要获取到以后线程的 Looper,很显然 Looper 的作用域就是线程并且不同线程具备不同的 Looper,这个时候能够通过 ThreadLocal 轻松获取。
不同线程中拜访同一个 ThreadLocal 对象的 set 或者 get 办法,它们对 ThreadLocal 对象所做的读写操作仅限于各自线程的外部。所以 ThreadLocal 能够在多个线程中互不烦扰的存储和批改数据。
ThreadLocal 的 set() 办法:
/**
* Sets the current thread's copy of this thread-local variable
* to the specified value. Most subclasses will have no need to
* override this method, relying solely on the {@link #initialValue}
* method to set the values of thread-locals.
*
* @param value the value to be stored in the current thread's copy of
* this thread-local.
*/
public void set(T value) {Thread t = Thread.currentThread();
ThreadLocalMap map = getMap(t);
if (map != null)
map.set(this, value);
else
createMap(t, value);
}
不同线程拜访同一个 ThreadLocal 对象的 set()办法时,ThreadLocal 会从各自线程 Thread t 中取出一个 ThreadLocalMap 对象,而后操作该线程的 ThreadLocalMap 对象。
ThreadLocal 的 get() 办法:
/**
* Returns the value in the current thread's copy of this
* thread-local variable. If the variable has no value for the
* current thread, it is first initialized to the value returned
* by an invocation of the {@link #initialValue} method.
*
* @return the current thread's value of this thread-local
*/
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();}
不同线程拜访同一个 ThreadLocal 对象的 get()办法时,ThreadLocal 会从各自线程 Thread t 中取出一个 ThreadLocalMap 对象,而后操作该线程的 ThreadLocalMap 对象。
MessageQueue
MessageQueue 次要蕴含两个操作:
- 插入 = enqueueMessage:往音讯队列中插入一条音讯
- 读取 + 删除 = next:从音讯队列中取出一条音讯并将其从队列中移除
Looper
Looper 次要扮演着音讯循环的角色,会不停的从 MessageQueue 中查看是否有新音讯,如果有新音讯就会立即解决,否则始终阻塞。
构造方法:
private Looper(boolean quitAllowed) {
// 创立一个 MessageQueue 音讯队列
mQueue = new MessageQueue(quitAllowed);
// 保留以后线程的对象
mThread = Thread.currentThread();}
创立 Looper:
new Thread("Thread#4") {
@Override
public void run() {super.run();
// 为以后线程创立 Looper
Looper.prepare();
Handler handler = new Handler();
// 开启音讯循环
Looper.loop();}
}.start();
因为主线程的 Looper 比拟非凡,所以 Looper 提供一个 getMainLooper 办法,通过它能够在任何中央获取到主线程的 Looper。
Looper 是能够退出的,Looper 提供了 quit 和 quitSafely 来退出一个 Looper,二者的区别是:quit 会间接退出 Looper,而 quitSafely 只是设定一个退出标记而后等音讯队列中的已有音讯处理完毕后才平安的退出。在子线程中,如果手动为其创立 Looper,那么在事件实现后二须要调用 quit 办法来终止音讯循环,否则这个子线程就会始终处于期待状态,如果退出 Looper 当前,线程会立即终止。
Looper 退出后,通过 Handler 发送的音讯会失败,这个时候 Handler 的 send 办法会返回 false。
loop():
/**
* Run the message queue in this thread. Be sure to call
* {@link #quit()} to end the loop.
*/
public static void loop() {final Looper me = myLooper();
if (me == null) {throw new RuntimeException("No Looper; Looper.prepare() wasn't called on this thread.");
}
if (me.mInLoop) {
Slog.w(TAG, "Loop again would have the queued messages be executed"
+ "before this one completed.");
}
me.mInLoop = true;
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();
// Allow overriding a threshold with a system prop. e.g.
// adb shell 'setprop log.looper.1000.main.slow 1 && stop && start'
final int thresholdOverride =
SystemProperties.getInt("log.looper."
+ Process.myUid() + "."
+ Thread.currentThread().getName()
+ ".slow", 0);
boolean slowDeliveryDetected = false;
for (;;) {
// 阻塞操作
Message msg = queue.next(); // might block
if (msg == null) {
// No message indicates that the message queue is quitting.
// 退出状态时才会返回 null
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);
}
// Make sure the observer won't change while processing a transaction.
final Observer observer = sObserver;
final long traceTag = me.mTraceTag;
long slowDispatchThresholdMs = me.mSlowDispatchThresholdMs;
long slowDeliveryThresholdMs = me.mSlowDeliveryThresholdMs;
if (thresholdOverride > 0) {
slowDispatchThresholdMs = thresholdOverride;
slowDeliveryThresholdMs = thresholdOverride;
}
final boolean logSlowDelivery = (slowDeliveryThresholdMs > 0) && (msg.when > 0);
final boolean logSlowDispatch = (slowDispatchThresholdMs > 0);
final boolean needStartTime = logSlowDelivery || logSlowDispatch;
final boolean needEndTime = logSlowDispatch;
if (traceTag != 0 && Trace.isTagEnabled(traceTag)) {Trace.traceBegin(traceTag, msg.target.getTraceName(msg));
}
final long dispatchStart = needStartTime ? SystemClock.uptimeMillis() : 0;
final long dispatchEnd;
Object token = null;
if (observer != null) {token = observer.messageDispatchStarting();
}
long origWorkSource = ThreadLocalWorkSource.setUid(msg.workSourceUid);
try {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();}
}
loop 办法是一个死循环,惟一跳出循环的形式是 MessageQueue 的 next 办法返回了 null。而当 Looper 的 quit 办法被调用时,Looper 就会调用 MessageQueue 的 quit 或者 quitSafely 办法来告诉音讯队列退出,当音讯队列被标记为退出状态时,它的 next 办法就会返回 null。也就是说,Looper 必须退出,否则 loop 办法会有限循环上来。
loop 办法调用 MessageQueue 的 next 办法来获取新音讯,next 办法是一个阻塞操作,当没有音讯时,next 办法会始终阻塞在那里,也导致 loop 办法始终阻塞。
当 next 办法返回新的音讯,Looper 就会解决这个音讯:msg.target.dispatchMessage(msg),这里的 msg.target 是发送这条音讯的 Handler 对象,这样 Handler 发送的音讯最终又会交给 Handler 的 dispatchMessage 办法来解决。Handler 的 dispatchMessage 办法是在创立 Handler 时所应用的 Looper 中执行的,这样就胜利将代码逻辑切换到指定线程中执行了。
Handler
/**
* Enqueue a message into the message queue after all pending messages
* before the absolute time (in milliseconds) <var>uptimeMillis</var>.
* <b>The time-base is {@link android.os.SystemClock#uptimeMillis}.</b>
* Time spent in deep sleep will add an additional delay to execution.
* You will receive it in {@link #handleMessage}, in the thread attached
* to this handler.
*
* @param uptimeMillis The absolute time at which the message should be
* delivered, using the
* {@link android.os.SystemClock#uptimeMillis} time-base.
*
* @return Returns true if the message was successfully placed in to the
* message queue. Returns false on failure, usually because the
* looper processing the message queue is exiting. Note that a
* result of true does not mean the message will be processed -- if
* the looper is quit before the delivery time of the message
* occurs then the message will be dropped.
*/
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);
}
private boolean enqueueMessage(@NonNull MessageQueue queue, @NonNull Message msg,
long uptimeMillis) {
msg.target = this;
msg.workSourceUid = ThreadLocalWorkSource.getUid();
if (mAsynchronous) {msg.setAsynchronous(true);
}
return queue.enqueueMessage(msg, uptimeMillis);
}
Handler 发送音讯的过程仅仅是向音讯队列插入一条音讯,MessageQueue 的 next 办法就会返回这条音讯给 Looper,Looper 收到音讯后就开始解决,最终音讯由 Looper 交由 Handler 的 dispatchMessage 办法解决,此时 Handler 进入音讯解决阶段。
音讯解决
dispatchMessage():
/**
* Handle system messages here.
*/
public void dispatchMessage(@NonNull Message msg) {if (msg.callback != null) {handleCallback(msg);
} else {if (mCallback != null) {if (mCallback.handleMessage(msg)) {return;}
}
handleMessage(msg);
}
}
首先查看 Message 的 callback 是否为 null,不为 null 就通过 handleCallback 来解决音讯,Message 的 callback 是一个 Runnable 对象,实际上就是 Handler 的 post 办法传递的 Runnable 参数。
handleCallback():
private static void handleCallback(Message message) {message.callback.run();
}
其次,查看 mCallback 是否为 null,不为 null 就调用 mCallback 的 handleMessage 办法来解决音讯。其中 Callback 是一个接口,其定义如下:
/**
* Callback interface you can use when instantiating a Handler to avoid
* having to implement your own subclass of Handler.
*/
public interface Callback {
/**
* @param msg A {@link android.os.Message Message} object
* @return True if no further handling is desired
*/
boolean handleMessage(@NonNull Message msg);
}
通过 Callback 能够采纳如下形式创立 Handler 对象:
Handler handler = new Handler(callback);
能够用来创立一个不派生 Handler 子类的 Handler 的对象。在日常开发中,创立 Handler 最常见的形式就是派生一个 Handler 的子类并重写其 handleMessage 办法来解决具体的音讯,而 Callback 给咱们提供了另外一种应用 Handler 的形式。
最初,调用 Handler 的 handleMessage 办法来解决音讯。
主线程的音讯循环
Android 的主线程是 ActivityThread,入口为 main 函数。在 main 函数中零碎会通过 Looper.prepareMainLooper()来创立主线程的 Looper 以及 MessageQueue,并通过 Looper.loop()来开启主线程的音讯循环。
public static void main(String[] args) {
......
Looper.prepareMainLooper();
// Find the value for {@link #PROC_START_SEQ_IDENT} if provided on the command line.
// It will be in the format "seq=114"
long startSeq = 0;
if (args != null) {for (int i = args.length - 1; i >= 0; --i) {if (args[i] != null && args[i].startsWith(PROC_START_SEQ_IDENT)) {
startSeq = Long.parseLong(args[i].substring(PROC_START_SEQ_IDENT.length()));
}
}
}
ActivityThread thread = new ActivityThread();
thread.attach(false, startSeq);
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.loop();
throw new RuntimeException("Main thread loop unexpectedly exited");
}
主线程的音讯循环开始之后,ActivityThread 须要一个 Handler 来和音讯队列进行交互,这个 Handler 就是 ActivityThread.H 类的对象,它外部定义了一组音讯类型,次要蕴含四大组件的启动、进行等过程:
class H extends Handler {
public static final int BIND_APPLICATION = 110;
@UnsupportedAppUsage
public static final int EXIT_APPLICATION = 111;
@UnsupportedAppUsage
public static final int RECEIVER = 113;
@UnsupportedAppUsage
public static final int CREATE_SERVICE = 114;
@UnsupportedAppUsage
public static final int SERVICE_ARGS = 115;
@UnsupportedAppUsage
public static final int STOP_SERVICE = 116;
public static final int CONFIGURATION_CHANGED = 118;
public static final int CLEAN_UP_CONTEXT = 119;
@UnsupportedAppUsage
public static final int GC_WHEN_IDLE = 120;
@UnsupportedAppUsage
public static final int BIND_SERVICE = 121;
@UnsupportedAppUsage
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 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;
@UnsupportedAppUsage
public static final int REMOVE_PROVIDER = 131;
public static final int DISPATCH_PACKAGE_BROADCAST = 133;
@UnsupportedAppUsage
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;
@UnsupportedAppUsage
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;
@UnsupportedAppUsage
public static final int INSTALL_PROVIDER = 145;
public static final int ON_NEW_ACTIVITY_OPTIONS = 146;
@UnsupportedAppUsage
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 LOCAL_VOICE_INTERACTION_STARTED = 154;
public static final int ATTACH_AGENT = 155;
public static final int APPLICATION_INFO_CHANGED = 156;
public static final int RUN_ISOLATED_ENTRY_POINT = 158;
public static final int EXECUTE_TRANSACTION = 159;
public static final int RELAUNCH_ACTIVITY = 160;
public static final int PURGE_RESOURCES = 161;
public static final int ATTACH_STARTUP_AGENTS = 162;
......
}
ActivityThread 通过 ApplicationThread 和 AMS 进行过程间通信,AMS 以过程间通信的形式来实现 ActivityThread 的申请后,回调 ApplicationThread 中的 Binder 办法,而后 ApplicationThread 会向 ActivityThread.H 发送音讯,ActivityThread.H 收到音讯后会将 ApplicationThread 中的逻辑切换到 ActivityThread 中执行,也即切换回主线程执行。这个过程,就是主线程的音讯循环模型。