Android消息处理机制——Handler

1.为什么要使用Handler?

子线程不能更改主线程的UI,在异步消息处理机制中,通过Handler完成从子线程到主线程的切换,完美解决子线程数据请求,主线程更新UI的问题

2.Handler基本原理

主线程里都维护了一个消息对列(message queue),子线程创建消息(Message),通过主线程里的Handler把消息发送到消息队列(message queue),在主线程里还有一个轮循器(looper),不断循环去取出消息,在检查消息对列里有没有新的消息,一旦发现有新的消息,looper就会交给Handler对象处理,否则处于阻塞等待状态,这时候Handler则调用自己的回调函数dispatchMessage(Message msg) 来更新UI或者其它操作。
handler原理机制

3.Handler结合源码分析

3.1 Message

Message :消息
线程间通讯的数据单元, 可携带需要的数据
创建对象: Message.obtain() --消息池 (字符串常量池,连接池,线程池)
封装数据
public int what //id 标识
public int arg1
public int arg2
public Object obj

创建消息的方法Message.obtain()

  	private static final int MAX_POOL_SIZE = 50;
  	...
    public static Message obtain() {
        synchronized (sPoolSync) {
            if (sPool != null) {
                Message m = sPool;
                sPool = m.next;
                m.next = null;
                m.flags = 0; // clear in-use flag
                sPoolSize--;
                return m;
            }
        }
        return new Message();
    }

通过消息池得到消息对象,消息池最大数量为50个,没有的话new一个新对象。

3.2 Handler处理器

Handler是Message的处理器,同时也负责消息的发送和移除的工作
发送即时消息: sendMessage(Message msg)
发送延时消息: sendMessageDelayed(Message msg, long time)
处理消息: handleMessage(Message msg) (回调方法)
移除还未处理的消息: removeMessages(int what)

Handler通过sendMessage方法发送消息到消息队列中去,最终都会交给enqueueMessage方法处理

 private boolean enqueueMessage(MessageQueue queue, Message msg, long uptimeMillis) {
 		//把当前Handler对象赋值给msg的成员变量target,保证了谁发送谁处理
        msg.target = this;
        if (mAsynchronous) {
            msg.setAsynchronous(true);
        }
        return queue.enqueueMessage(msg, uptimeMillis);
    }

在该方法中将Handler对象赋值给msg的成员变量target,保证了谁发送谁处理。最后交给MessageQueue的enqueueMessage()方法处理。

3.3 MessageQueue消息队列

看MessageQueue的enqueueMessage()方法里面到底做了什么

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

用来存放通过Handler发送的消息,它是一个按Message的when排序的优先级队列。(when代表着被处理的时间)

3.4 Looper 循环器

负责循环取出Message Queue里面的当前需要处理的Message
交给对应的Handler进行处理
处理完后, 将Message缓存到消息池中, 以备复用

那么疑问来了?Looper什么时候取的消息呢?
Looper是什么时候创建的呢?
同时前面也没说MessageQueue是什么时候创建的呢?

解答这个问题之前先要明白我们的开打一个应用程序为什么可以一直运行呢?方法入口又在哪里呢?
答案就是在ActivityThread这个类里面,看看都干了什么

    public static void main(String[] args) {
        ....
        Looper.prepareMainLooper();

        ActivityThread thread = new ActivityThread();
        thread.attach(false);

        ...
        Looper.loop();
        ...
    }

main方法调用了 Looper.prepareMainLooper(),进去看一下

public static void prepareMainLooper() {
        prepare(false);
        synchronized (Looper.class) {
            if (sMainLooper != null) {
                throw new IllegalStateException("The main Looper has already been prepared.");
            }
            sMainLooper = myLooper();
        }
    }

prepare(false)干了什么呢?

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

sThreadLocal用于存储线程内的数据,sThreadLocal.set(new Looper(quitAllowed))创建了Looper对象,构造方法进去看一下呗

private Looper(boolean quitAllowed) {
        mQueue = new MessageQueue(quitAllowed);
        mThread = Thread.currentThread();
    }

这里又创建了MessageQueue,也就是说一个Looper对应位置的MessageQueue,进行了关联。

创建了Looper后,sMainLooper = myLooper()又干了什么?

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

这时候主线程就得到了这个创建的Looper。
回到main方法 最后又执行了 Looper.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.");
        }
        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;
            }
            ...
            try {
                msg.target.dispatchMessage(msg);
                dispatchEnd = needEndTime ? SystemClock.uptimeMillis() : 0;
            } finally {
                if (traceTag != 0) {
                    Trace.traceEnd(traceTag);
                }
            }   
           ...
            msg.recycleUnchecked();
        }
    }

代码很长,不需要全看,抽取关键性的代码

final Looper me = myLooper();拿到前面在主线程创建的looper
for (;;) {
Message msg = queue.next(); // 从消息队列不断取出消息
if (msg == null) {
// 没有消息的时候退出循环.
return;
}

try {
//这个方法用于分发消息,交给handler处理,target指定是谁发的就有谁处理
msg.target.dispatchMessage(msg);
}
}

这是个死循环,这也就解释了为什么打开的应用可以一直运行,除非手动退出程序,没有了消息才会return退出程序,否则一直读取消息,并分发出去

3.5 dispatchMessage消息的分发处理

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

这个有三个方法可以处理,

  1. handleCallback(msg);
    当创建的消息有callback时,由message自己处理,举例:
	Handler handler = new Handler();
	handler.post(new Runnable() {
	    @Override
	    public void run() {
	    //UI操作
	    }
	});
  1. mCallback.handleMessage(msg)
    当创建的Handler有callback(内部接口)时,由callback自己处理,举例:
   Handler.Callback callback = new Handler.Callback() {
       @Override
       public boolean handleMessage(Message msg) {
       		//UI操作
           return false;
       }
   };
   Handler handler = new Handler(callback);
   //子线程发送消息
   handler.sendMessage(msg);
  1. handleMessage(msg) 举例:
     Handler handler = new Handler(){
          @Override
          public void handleMessage(Message msg) {
              //UI操作
          }
      };
	  //子线程发消息
	  handler.sendMessage(message);

再附一张原理图
handler原理
留下几个问题供参考?
1.Handler的post方法和sendMessage方法区别是什么?
2.可以在子线程创建Handler吗?如何创建?
3.一个线程可以有多个Handler、Looper、MessegeQueue吗?

发布了28 篇原创文章 · 获赞 1 · 访问量 527

猜你喜欢

转载自blog.csdn.net/qq_40575302/article/details/104535997