Android消息机制(2)

在Android 中,线程内部或者线程之间进行信息交互时经常会使用消息,这些基础的东西如果我们熟悉其内部的原理,将会使我们容易、更好地架构系统,避免一些低级的错误。

下面我们分析下程序的运行过程:

1.onCreate()

首先启动服务时将会调用onCreate()方法,在该方法中我们new了一个HandlerThread对象,提供了线程的名字和优先级。

紧接着我们调用了start()方法,执行该方法将会调用HandlerThread对象的run()方法:

  1. public void run() {
  2. mTid = Process.myTid();
  3. Looper.prepare();
  4. synchronized (this) {
  5. mLooper = Looper.myLooper();
  6. notifyAll();
  7. }
  8. Process.setThreadPriority(mPriority);
  9. onLooperPrepared();
  10. Looper.loop();
  11. mTid = -1;
  12. }

在run()方法中,系统给线程添加的Looper,同时调用了Looper的loop()方法:

  1. public static final void loop() {
  2. Looper me = myLooper();
  3. MessageQueue queue = me.mQueue;
  4. while (true) {
  5. Message msg = queue.next(); // might block
  6. //if (!me.mRun) {
  7. //    break;
  8. //}
  9. if (msg != null) {
  10. if (msg.target == null) {
  11. // No target is a magic identifier for the quit message.
  12. return;
  13. }
  14. if (me.mLogging!= null) me.mLogging.println(
  15. ">>>>> Dispatching to " + msg.target + " "
  16. + msg.callback + ": " + msg.what
  17. );
  18. msg.target.dispatchMessage(msg);
  19. if (me.mLogging!= null) me.mLogging.println(
  20. "<<<<< Finished to    " + msg.target + " "
  21. + msg.callback);
  22. msg.recycle();
  23. }
  24. }
  25. }

通过源码我们可以看到loop()方法是个死循环,将会不停的从MessageQueue对象中获取Message对象,如果 MessageQueue 对象中不存在Message对象,则结束本次循环,然后继续循环;如果存在Message对象,则执行 msg.target.dispatchMessage(msg),但是这个msg的.target字段的值是什么呢?我们先暂时停止跟踪源码,返回到 onCreate()方法中。线程执行完start()方法后,我们可以获取线程的Looper对象,然后new一个ServiceHandler对象, 我们把Looper对象传到ServiceHandler构造函数中将使handler、looper和messageQueue三者建立联系。

2.onStartCommand()

执行完onStart()方法后,将执行onStartCommand()方法。首先我们从消息池中获取一个Message实例,然后给 Message对象的arg1、what、obj三个字段赋值。紧接着调用sendMessage(msg)方法,我们跟踪源代码,该方法将会调用 sendMessageDelayed(msg, 0)方法,而sendMessageDelayed()方法又会调用sendMessageAtTime(msg, SystemClock.uptimeMillis() + delayMillis)方法,在该方法中我们要注意该句代码msg.target = this,msg的target指向了this,而this就是ServiceHandler对象,因此msg的target字段指向了 ServiceHandler对象,同时该方法又调用MessageQueue 的enqueueMessage(msg, uptimeMillis)方法:

  1. final boolean enqueueMessage(Message msg, long when) {
  2. if (msg.when != 0) {
  3. throw new AndroidRuntimeException(msg
  4. + " This message is already in use.");
  5. }
  6. if (msg.target == null && !mQuitAllowed) {
  7. throw new RuntimeException("Main thread not allowed to quit");
  8. }
  9. synchronized (this) {
  10. if (mQuiting) {
  11. RuntimeException e = new RuntimeException(
  12. msg.target + " sending message to a Handler on a dead thread");
  13. Log.w("MessageQueue", e.getMessage(), e);
  14. return false;
  15. } else if (msg.target == null) {
  16. mQuiting = true;
  17. }
  18. msg.when = when;
  19. //Log.d("MessageQueue", "Enqueing: " + msg);
  20. Message p = mMessages;
  21. if (p == null || when == 0 || when < p.when) {
  22. msg.next = p;
  23. mMessages = msg;
  24. this.notify();
  25. } else {
  26. Message prev = null;
  27. while (p != null && p.when <= when) {
  28. pprev = p;
  29. pp = p.next;
  30. }
  31. msg.next = prev.next;
  32. prev.next = msg;
  33. this.notify();
  34. }
  35. }
  36. return true;
  37. }

该方法主要的任务就是把Message对象的添加到MessageQueue中(数据结构最基础的东西,自己画图理解下)。

handler.sendMessage()-->handler.sendMessageDelayed()-->handler.sendMessageAtTime()-->msg.target = this;queue.enqueueMessage==>把msg添加到消息队列中

3.handleMessage(msg)

onStartCommand()执行完毕后我们的Service中的方法就执行完毕了,那么handleMessage()是怎么调用的呢?在前 面分析的loop()方法中,我们当时不知道msg的target字段代码什么,通过上面分析现在我们知道它代表ServiceHandler对 象,msg.target.dispatchMessage(msg);则表示执行ServiceHandler对象中的 dispatchMessage()方法

  1. public void dispatchMessage(Message msg) {
  2. if (msg.callback != null) {
  3. handleCallback(msg);
  4. } else {
  5. if (mCallback != null) {
  6. if (mCallback.handleMessage(msg)) {
  7. return;
  8. }
  9. }
  10. handleMessage(msg);
  11. }
  12. }

该方法首先判断callback是否为空,我们跟踪的过程中未见给其赋值,因此callback字段为空,所以最终将会执行handleMessage()方法,也就是我们ServiceHandler类中复写的方法。在该方法将根据what字段的值判断执行哪段代码。

至此,我们看到,一个Message经由Handler的发送,MessageQueue的入队,Looper的抽取,又再一次地回到Handler的怀抱中。而绕的这一圈,也正好帮助我们将同步操作变成了异步操作。

上一篇:application Initialization设置导致处理程序ExtensionlessUrlHandler-Integrated-4.0在其模块列表中有一个错误模块问题的解决


下一篇:Elasticsearch 分词器