Android进阶(1)理解Handler机制(源码分析)

本文详细探讨了Android中Handler的使用场景,解释了为何在主线程中需要避免耗时操作,以及Handler如何协助子线程安全更新UI。文章剖析了涉及Handler的类,如ActivityThread、ThreadLocal、Message、MessageQueue和Looper的工作流程,阐述了消息如何入列和出列。此外,还解释了Looper.loop的死循环为何不会阻塞线程,并分析了其对CPU资源的影响。
摘要由CSDN通过智能技术生成

1.什么是Handler?为什么要用Handler

  • android在主线程中不建议做耗时操作(ANR),而子线程中更新UI是线程不安全的(Only the original thread that created a view hierarchy can touch its views

  • Handler的作用就是通过使用Handler完成主线程和子线程信息的传递,从而达到刷新UI的效果

2.Handler涉及到的类

  • ActivityThread
  • ThreadLocal
  • Message
  • MessageQueue
  • Loop

3.Handler如何将消息入列

  • ActivityThread 中的main方法中调用Looper.prepareMainLooper->prepare(此处注意一个异常 Only one Looper may be created per thread) 初始化Looper 对象并将其交给ThreadLocal

    ActivityThread.java

      public static void main(String[] args) {
       	...省略
    
      	Looper.prepareMainLooper();
    
      	ActivityThread thread = new ActivityThread();
      	thread.attach(false);
    
     		...省略
      	Looper.loop();
    
      	throw new RuntimeException("Main thread loop unexpectedly exited");
      }
    

    Looper.java

       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));
      }
    
     
      public static void prepareMainLooper() {
          prepare(false);
          synchronized (Looper.class) {
              if (sMainLooper != null) {
                  throw new IllegalStateException("The main Looper has already been prepared.");
              }
              sMainLooper = myLooper();
          }
      }
    
  • Looper 的构造方法中初始化了MessageQueue

    Looper.java

      private Looper(boolean quitAllowed) {
      	        mQueue = new MessageQueue(quitAllowed);
      	        mThread = Thread.currentThread();
      	 }	 
    
  • 当调用handler.sendEmptyMessage->sendEmptyMessageDelayed->sendMessageDelayed->sendMessageAtTime->enqueueMessage 时时将当前Handler 对象通过msg.target=thisMessage 一个引用

    Handler.java

      public final boolean sendEmptyMessage(int what) {
              return sendEmptyMessageDelayed(what, 0);
      }
      
      public final boolean sendEmptyMessageDelayed(int what, long delayMillis) {
          Message msg = Message.obtain();
          msg.what = what;
          return sendMessageDelayed(msg, delayMillis);
      }
    
      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;
          if (mAsynchronous) {
              msg.setAsynchronous(true);
          }
          return queue.enqueueMessage(msg, uptimeMillis);
      }
    
  • 最后调用MessageQueue.enqueueMessage 将消息入列

    MessageQueue.java

      boolean enqueueMessage(Message msg, long when) {
     
    
      synchronized (this) {
    
       ...省略
    
          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 {
      
              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;
    

    }

4.Handler如何消息出列

  • ActivityThread 中的main方法中调用Looper.loop 方法

    ActivityThread.java

      public static void main(String[] args) {
       	...省略
    
      	Looper.prepareMainLooper();
    
      	ActivityThread thread = new ActivityThread();
      	thread.attach(false);
    
     		...省略
      	Looper.loop();
    
      	throw new RuntimeException("Main thread loop unexpectedly exited");
      }
    
  • loop方法中的死循环不断调用MessageQueue.next将消息取出

    Looper.java

      public static void loop() {
          final Looper me = myLooper();
         
          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);
                  end = (slowDispatchThresholdMs == 0) ? 0 : SystemClock.uptimeMillis();
              } finally {
                  if (traceTag != 0) {
                      Trace.traceEnd(traceTag);
                  }
              }
    
             ...省略
          }
      }
    
  • 每个Message都持有一个发送者(Handler)的引用,当取出 Message 后调用 msg.target.dispatchMessage(msg) 将消息发送到handlerMessagecallBack

    Handler.java

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

5.Looper.loop是个死循环为什么没有阻塞线程?

  • 创建 Service、Activity 等包括执行其生命周期,最后都是交由 ActivityThread.H 处理,所以 Looper 虽然死循环,但是本质上我们UI的展示、更新,是通过 Handler 来处理,所以并不会造成真正的UI阻塞。

  • ActivityThread 实际上就是开启了一个消息循环,来执行 Activity、Service 等等的相关操作,一旦这个消息循环停止了,则意味着App进程也结束了。真正会卡死主线程的操作是在回调方法onCreate/onStart/onResume等操作时间过长,会导致掉帧,甚至发生ANR,looper.loop本身不会导致应用卡死。所以会阻塞,但是不会卡住。

  • 那又会有另一个问题主线程的死循环一直运行是不是特别消耗CPU资源呢? 简单说就是在主线程的MessageQueue 没有消息时,便阻塞在**queue.next()中的nativePollOnce()**方法里,此时主线程会释放CPU资源进入休眠状态,直到下个消息到达或者有事务发生,所以说,主线程大多数时候都是处于休眠状态,并不会消耗大量CPU资源

    MessageQueue.java

      Message next() {
           
      	...省略
      	
          for (;;) {
              if (nextPollTimeoutMillis != 0) {
                  Binder.flushPendingCommands();
              }
    
              nativePollOnce(ptr, nextPollTimeoutMillis);
    
      	...省略	             
    
          }
      }
    
能力有限,理解到此,如有错误,请联系改正
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值