安卓异步通信:Handler源码分析

核心类方法浅析

Handler:
sendMessage/post:将消息发送到消息队列中
dispatchMessage:将消息分发给对应Handler
handleMessage:依据消息进行相关处理/操作

MessageQueue:
enqueueMessage:将消息依据时间放入消息队列(入队)
next:从消息队列取出消息(出队)

Looper:
prepare:创建一个循环器+消息队列实例
loop:消息循环(即从消息队列取出消息并发给Handler)

源码分析

依旧采用由使用步骤深入分析

Handler.sendMessage()

①创建Handler对象:

实际调用:

public Handler() {
   this(null, false);
}
public Handler(Callback callback, boolean async) {
          mLooper = Looper.myLooper();
          if (mLooper == null) {
              throw new RuntimeException(
                  "Can't create handler inside thread that has not called Looper.prepare()");
          }

          mQueue = mLooper.mQueue;
}

创建Handler对象的过程也就是将Handler绑定至循环器+消息队列的过程:通过myLooper获取当前线程的循环器对象并赋值绑定、由循环器获得消息队列进行赋值绑定。
此处发现用来绑定的循环器和消息队列并没有在构造方法中创建,那么这两个实例是何时生成的?

注:①之前的隐式操作:循环器+消息队列实例生成、消息循环开始
上述描述中循环器通过Looper.prepare进行生成,而该方法在安卓应用启动时即被调用生成:

publicstatic void main(String[] args) {
    ...

    Looper.prepareMainLooper(); 
    ActivityThread thread = new ActivityThread(); 
    // 创建主线程
    Looper.loop(); 
    // 自动开启 消息循环

}

通过主线程调用prepareMainLooper创建应用的主线程循环器

public static final void prepare() {
   
    if (sThreadLocal.get() != null) {
        throw new RuntimeException("Only one Looper may be created per thread");
    }

    sThreadLocal.set(new Looper(true));
}

prepare方法首先进行是否重复调用判断(ThreadLocal是否已存在)
然后再生成该线程的循环器并设置进去

private Looper(boolean quitAllowed) {

    mQueue = new MessageQueue(quitAllowed);

    mRun = true;
    mThread = Thread.currentThread();
}

循环器构造方法中会生成对应的消息队列,并将当前线程与其绑定起来
上述分析了主线程循环器的创建+子线程由手动创建循环器发生的一系列操作

在循环器+消息队列创建成功后,消息的循环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(); 
        if (msg == null) {
            return;
        }

        msg.target.dispatchMessage(msg);

        msg.recycle();
        }
}

消息循环开启:首先通过相关循环器获取消息队列,遍历消息将每个消息发送至其对应Handler,发送完成后回收资源

消息遍历过程next():

  Message next() {
	    ...

	    // 该参数用于确定消息队列中是否还有消息
	    // 从而决定消息队列应处于出队消息状态 or 等待状态
	    int nextPollTimeoutMillis = 0;

	    for (;;) {
	        if (nextPollTimeoutMillis != 0) {
	            Binder.flushPendingCommands();
	        }

	    // nativePollOnce方法在native层,若是nextPollTimeoutMillis为-1,此时消息队列处于等待状态 
	    nativePollOnce(ptr, nextPollTimeoutMillis);

	    synchronized (this) {
	 
	        final long now = SystemClock.uptimeMillis();
	        Message prevMsg = null;
	        Message msg = mMessages;

	        // 出队消息,即 从消息队列中取出消息:按创建Message对象的时间顺序
	        if (msg != null) {
	            if (now < msg.when) {
	                nextPollTimeoutMillis = (int) Math.min(msg.when - now, Integer.MAX_VALUE);
	            } else {
	                // 取出了消息
	                mBlocked = false;
	                if (prevMsg != null) {
	                    prevMsg.next = msg.next;
	                } else {
	                    mMessages = msg.next;
	                }
	                msg.next = null;
	                if (DEBUG) Log.v(TAG, "Returning message: " + msg);
	                msg.markInUse();
	                return msg;
	            }
	        } else {

	            // 若 消息队列中已无消息,则将nextPollTimeoutMillis参数设为-1
	            // 下次循环时,消息队列则处于等待状态
	            nextPollTimeoutMillis = -1;
	        }

	        ......
	    }
	       .....
	   }
}

loop会进行消息循环取出操作(无限for循环),包含:①通过nextPollTimeoutMillis控制下一个消息出队时间及循环等待状态 ②有消息时进行消息出队相关操作

消息分发过程dispatchMessage(msg):

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

            handleMessage(msg);
        }
    }

通过msg内容是否包含callBack判断执行哪种通信方式(sendMessage/post):sendMessage:调用handleMessage;post:调用handleCallBack(即调用传入的run())

所以第一步整体执行的操作:
隐式:①主线程自动生成循环器+消息队列(子线程手动生成)
②开启消息循环(loop()),循环将消息出队并分发给对应Handler
显示:创建Handler实例(与对应循环器+消息队列绑定)

②创建消息对象
Message msg = Message.obtain(); // 实例化消息对象
msg.what = 1; // 消息标识
msg.obj = "AA"; // 消息内容存放

源码分析:

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

obtain实际是从消息池中取出可用消息对象进行复用(若池子用完则创建新实例使用)

③发送信息sendMessage
public final boolean sendMessage(Message msg)
  {
      return sendMessageDelayed(msg, 0);
  }

发送信息实际调用sendMessageDelayed,逐层向下分析

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;

        return enqueueMessage(queue, msg, uptimeMillis);
    }

上述获取消息队列,用于准备将消息放入队列

private boolean enqueueMessage(MessageQueue queue, Message msg, long uptimeMillis) {
     msg.target = this;       

    return queue.enqueueMessage(msg, uptimeMillis);
}

该步将对应Handler记录到msg中,以便分发时调用,然后再消息入队

boolean enqueueMessage(Message msg, long when) {
   ...

   synchronized (this) {
       msg.markInUse();
       msg.when = when;
       Message p = mMessages;
       boolean needWake;

       // 判断消息队列里有无消息
           // a. 若无,则将当前插入的消息 作为队头 & 若此时消息队列处于等待状态,则唤醒
           if (p == null || when == 0 || when < p.when) {
               msg.next = p;
               mMessages = msg;
               needWake = mBlocked;
           } else {
               needWake = mBlocked && p.target == null && msg.isAsynchronous();
               Message prev;

           // b. 判断消息队列里有消息,则根据 消息(Message)创建的时间 插入到队列中
               for (;;) {
                   prev = p;
                   p = p.next;
                   if (p == null || when < p.when) {
                       break;
                   }
                   if (needWake && p.isAsynchronous()) {
                       needWake = false;
                   }
               }

               msg.next = p; 
               prev.next = msg;
           }

           if (needWake) {
               nativeWake(mPtr);
           }
       }
       return true;
}

放入队列操作:判断当前队列是否有消息(相当于判断循环状态)①有消息:依据时间节点插入合适位置 ②没有消息:当前消息作为头部放入,并判断是否需要唤醒

上述一系列信息发送操作实质:
将消息与其目标Handler绑定起来,再依据消息时间放入消息队列等待循环出队

至此,sendMessage流程即分析完毕,上述黑体字就是整个流程的关键操作

Handler.post()

①主线程创建handler实例

此步骤同上述sendMessage方法,进行隐式处理、绑定等动作

②工作线程发送信息
mHandler.post(new Runnable() {
       @Override
       public void run() {
           ... // 需执行的UI操作 
       }

});

post方法的处理,逐层深入:

public final boolean post(Runnable r)
   {
      return  sendMessageDelayed(getPostMessage(r), 0);
   }
private static Message getPostMessage(Runnable r) {
    Message m = Message.obtain();
    
    m.callback = r;
    return m;
}
public final boolean sendMessageDelayed(Message msg, long delayMillis)
 {
     if (delayMillis < 0) {
         delayMillis = 0;
     }

     return sendMessageAtTime(msg, SystemClock.uptimeMillis() + delayMillis);
 }

从sendMessageDelayed开始就与sendMessage()相同了
上述操作就是将post传入的runnable实例封装成一个message,再进行消息发送等任务,剩余就和发送消息处理完全相同。

循环中消息处理:

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(); 
      if (msg == null) {
          return;
      }
      msg.target.dispatchMessage(msg);
      msg.recycle();
      }
}
public void dispatchMessage(Message msg) {
      if (msg.callback != null) {
          handleCallback(msg);
      } else {
          if (mCallback != null) {
              if (mCallback.handleMessage(msg)) {
                  return;
              }
          }
          handleMessage(msg);
      }
  }

在dispatchMessage中,因为之前封装消息时,将run赋值给了callBack,所以此处处理情况与sendMessage不同,触发handleCallback

private static void handleCallback(Message message) {
    message.callback.run();
}

该方法就直接调用先前runnable实例中实现的run方法

至此post实现过程分析完毕,与sendMessage实际只多了封装消息步骤与run方法调用

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

魔幻音

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值