我们知道,更新ui等一些耗时操作都不能放在主线程去执行,最好在子线程中执行,那我们执行好的任务又怎么通知主线程去更新数据呢?答案就是Handler机制
Handler机制里又几个重要的东西:
整个handler主要运行在子线程相对的主线程中,子线程通过sendMessage吧Message发送到handler,并设置和这个handler绑定在一起,handler把消息放进从looper拿到的MessageQueue,looper会不断循环去取到MessageQueue里的Message,然后又分发到Message绑定的handler进行处理。整个过程就是个回调的过程
我们从源码分析:
首先去看ActivityThread这个类的main方法,也就是程序入口:(这个类看起来很像个子线程,但并不是,它没有继承Thread)
public static void main(String[] args) {
Trace.traceBegin(Trace.TRACE_TAG_ACTIVITY_MANAGER, "ActivityThreadMain");
// 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("" );
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");
}
首先Looper.prepareMainLooper();
准备一个Looper
public static void prepareMainLooper() {
prepare(false);
synchronized (Looper.class) {
if (sMainLooper != null) {
throw new IllegalStateException("The main Looper has already been prepared.");
}
sMainLooper = myLooper();
}
}
sMainLooper = myLooper();
/**
* Return the Looper object associated with the current thread. Returns
* null if the calling thread is not associated with a Looper.
*/
public static @Nullable Looper myLooper() {
return sThreadLocal.get();
}
从sThreadLocal中获取Looper()
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();
}
这段代码实现了一个线程只能获取对应looper,不能获取他人的。
然后回去
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();
获取handler,这个handler处理的消息几乎是整个app工作流程
开启looper:看看
public static void 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;
// 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.
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();
}
}
直接给你来个死循环,既能不断去消息分发,又能保证程序一直存活,那为什么不会阻塞整个app运行呢?
我们看到24行那Message msg = queue.next(); // might block
有一段注释:有可能阻塞,也就是当队列为空时会阻塞,直到下一个消息进来,这就是linux的epoll//pipe机制,从这个next()
方法进去会发现有个nativePollOnce()
本地方法,这就是阻塞的地方,可想而知底层代码肯定有睡眠和唤醒机制。还记得
thread.attach(false, startSeq);
这个方法吗,它绑定一个binder线程,这个binder线程又会一直与bingder驱动进行沟通。我们知道binder驱动就是用于进程间通信的,关键就在这了,android系统进程会通过binder与我们的app进程通信!当我们点击屏幕,就会通过binder传到app的handler消息机制往队列塞消息。这就使app又动起来了
一个自定义handler机制的例子:
Message:
class Message {
var target:Handler?=null
var what: Int = 0
var obj : Any? = null
}
MessageQueue:(用到了生产者消费者模式)
class MessageQueue {
var putIndex:Int = 0
var takeIndex:Int = 0
var count:Int = 0
private var lock: Lock? = null
private var notEmpty: Condition? = null
private var notFull: Condition? = null
var items:Array<Message?>
init {
items = Array(20, {null})
this.lock = ReentrantLock()
this.notEmpty = (lock as ReentrantLock).newCondition()
this.notFull = (lock as ReentrantLock).newCondition()
}
fun enqueueMessage(msg:Message) {
try {
lock?.lock()
while (count == items.size){
notFull?.await()
}
items?.set(putIndex, msg)
putIndex = if (++putIndex == items?.size) 0 else putIndex
count++
notEmpty?.signalAll()
}finally {
lock?.unlock()
}
}
fun next():Message?{
var msg: Message? = null
try {
lock?.lock()
while (count==0){
notEmpty?.await()
}
items.let {
msg = it?.get(takeIndex)
it?.set(takeIndex, null)
takeIndex = if (++takeIndex == items?.size) 0 else takeIndex
count--
notFull?.signalAll()
}
}finally {
lock?.unlock()
}
return msg;
}
}
Looper:
class Looper {
var mQueue:MessageQueue? = null
init {
this.mQueue=MessageQueue()
}
companion object{
val sThreadLocal = ThreadLocal<Looper>()
fun prepare(){
if (sThreadLocal.get()!=null){
throw RuntimeException("error")
}
sThreadLocal.set(Looper())
}
fun myLooper(): Looper? {
return sThreadLocal.get()
}
fun loop(){
val me = myLooper()
if(me == null){
throw RuntimeException("error1")
}
val queue = me.mQueue
while (true){
val msg = queue?.next()
if(msg == null){
continue
}
msg.target?.dispatchMessage(msg)
}
}
}
}
Handler:
open class Handler {
private var mQueue:MessageQueue? = null
private var mLooper:Looper?=null
init {
mLooper = Looper.myLooper()
this.mQueue = mLooper?.mQueue
}
fun sendMessage(msg:Message){
msg.target=this
mQueue?.enqueueMessage(msg)
}
open fun handleMessage(msg:Message){
Log.i("Hanlder", msg.obj.toString())
}
fun dispatchMessage(msg:Message){
handleMessage(msg)
}
}
MainActivity:
class MainActivity : AppCompatActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
Looper.prepare()
val handler:Handler = object :Handler(){
override fun handleMessage(msg: Message) {
System.out.println(Thread.currentThread().name+",received:"+msg.obj.toString())
}
}
for (i in 1..5){
Thread(object :Runnable{
override fun run() {
val msg = Message()
msg.what = 1
synchronized(UUID::class.java){
msg.obj = "收到线程"+Thread.currentThread().name+"发过来的信息"
}
handler.sendMessage(msg)
try {
Thread.sleep(1000)
}catch (e:Exception){
e.printStackTrace()
}
}
}).start()
}
Looper.loop()
}
}
只是为了好理解,这个例子还是会阻塞主线程的