Handler

2022-08-28  本文已影响0人  内卷程序员

android开发中,在子线程中进行一些操作完成后会通过handler发送一些数据给主线程。 生产者-消费者模型:生产者和消费者在同一时间段内共用同一个存储空间,生产者往存储空间中添加数据, 消费者从存储空间中取走数据。跨线程的核心就是共享内存。

handler整体流程

image.png

子线程 - 将消息插入队列的节点

handler -> sendMessage -> enqueueMessage -> messasgeQueue.enqueueMessage

主线程 - 将消息从队列里面取出分发

looper.loop() -> messasgeQueue.next() -> handler.dispatchMessage() -> handler.handleMessage()

image.png

一、Handler的创建是与Looper创建的线程是相同的。
二、Looper中内部维护了一个MessageQueue(也就是消息队列)。且该队列是通过链表的形式实现优先级队列。
三、Hanlder最终通过sendMessage方法将消息发送到Looper中对应的MessageQueue中。
四、Looper通过消息循环获取消息后,会调用对应的消息中的target(target对应的是发消息的Handler)的dispatchMessage()方法来处理消息。

Looper原理

class ActivityThread {

 public static void main(String[] args) {
        ...
       //准备主线程looper
        Looper.prepareMainLooper();
        ActivityThread thread = new ActivityThread();
        thread.attach(false);
        if (sMainThreadHandler == null) {
            sMainThreadHandler = thread.getHandler();
        }
        ...
        Trace.traceEnd(Trace.TRACE_TAG_ACTIVITY_MANAGER);
       //启动 Looper 开启消息循环
        Looper.loop();
       ...
    }
}
public final class Looper {

  final MessageQueue mQueue;
  final Thread mThread;

  //Looper内部会创建MessageQueue对象
  private Looper(boolean quitAllowed) {
        mQueue = new MessageQueue(quitAllowed);
        mThread = Thread.currentThread();
    }

   //创建主线程Looper对象 判断looper是否被创建 保存主线程的looper对象
   public static void prepareMainLooper() {
      //false表示消息队列不能被清除
        prepare(false);
        synchronized (Looper.class) {
            if (sMainLooper != null) {
                throw new IllegalStateException("The main Looper has already been prepared.");
            }
            //当前Looper对象已经与主线程关联了
            sMainLooper = myLooper();
        }
    }
  //Looper与当前主线程绑定
  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));//创建Looper对象,放入主线程局部变量中
    }
  //获取当前主线程的Looper对象
  public static @Nullable Looper myLooper() {
        return sThreadLocal.get();
   }
 
//当前Looper对象与主线程关联后,接着会调用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(); //该方法可能堵塞,
            if (msg == null) {
                //如果没有消息,表示当前消息队列已经退出
                return;
            }
           //...省略部分代码
            try {
             //获取消息后,执行发送消息的handler的dispatchMessage方法。
                msg.target.dispatchMessage(msg);
                end = (slowDispatchThresholdMs == 0) ? 0 : SystemClock.uptimeMillis();
            } finally {
                if (traceTag != 0) {
                    Trace.traceEnd(traceTag);
                }
            }
           //...省略部分代码
            }
            msg.recycleUnchecked();
        }
  //quitSafely相比于quit方法安全之处在于清空消息之前会派发所有的非延迟消息。无论是调用了quit方法还是quitSafely方法只会,Looper就不再接收新的消息
    public void quit() {
        mQueue.quit(false);
    }
 
    public void quitSafely() {
        mQueue.quit(true);
    }
    }

MessageQueue 原理 - 入队出队

class MessageQueue{

    void quit(boolean safe) {
        synchronized (this) {
            if (mQuitting) {
                return;
            }
            mQuitting = true;

            if (safe) {
              // 清空消息之前会派发所有的非延迟消息
                removeAllFutureMessagesLocked();
            } else {
              //清空全部消息
                removeAllMessagesLocked();
            }

            // We can assume mPtr != 0 because mQuitting was previously false.
            nativeWake(mPtr);
        }
    }


//消息队列的加入过程
boolean enqueueMessage(Message msg, long when) {
          //...省略部分代码
        synchronized (this) {
          //...省略部分代码
            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 {
              //...省略部分代码
                //循环遍历消息队列,把当前进入的消息放入合适的位置(比较等待时间)
                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;
            }
          //...省略部分代码
        }
        return true;
     }

   //MessageQueue中去获取消息,直到获取消息后才会退出
  Message next() {
    //...省略部分代码
     for (;;) {
         nativePollOnce(ptr, nextPollTimeoutMillis);//睡眠
         synchronized (this) {
         //...省略部分代码
         final long now = SystemClock.uptimeMillis();
          Message prevMsg = null;
          Message msg = mMessages;
          if (msg != null && msg.target == null) {
             // 同步屏障,类似于救护车需要优先通过执行,比如更新UI,先发送同步屏障,然后再发送同步消息,循环所有消息,发现有同步消息并且是更新UI 马上出来 Async 表示刷新UI消息
             do {
                   prevMsg = msg;
                   msg = msg.next;
                } while (msg != null && !msg.isAsynchronous());
              }
         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 {
                    // No more messages.
                    nextPollTimeoutMillis = -1; //没有消息就一直睡眠
                }
                //
                if (mQuitting) {
                    dispose();
                    return null;
                }
      }
    }
}

Handler的原理

public class Handler {

//不带Looper的构造函数,是通过Looper.myLooper()来获取当前主线程的Looper对象 
  public Handler() {this(null, false);}
  public Handler(boolean async) {this(null, async);}
  public Handler(Callback callback) {this(callback, false);}
  public Handler(boolean async) {this(null, async);}
  public Handler(Callback callback, boolean async) {
        //Looper.myLooper()内部会调用sThreadLocal.get(),获取线程中保存的looper局部变量
        mLooper = Looper.myLooper();
        if (mLooper == null) {
            throw new RuntimeException(
                "Can't create handler inside thread that has not called Looper.prepare()");
        }
        //获取当前Looper中的MessageQueue
        mQueue = mLooper.mQueue;
        mCallback = callback;
        mAsynchronous = async;
    }
 //带Looper参数的构造函数是线程已经通过Looper.prepare()与Looper.loop()构建了自己的循环消息队列, 只有调用了该方法后,才会将当前Looper对象放入线程的局部变量中**可以构建自己的消息处理循环,比如HandlerThread 
  public Handler(Looper looper) { this(looper, null, false); }
  public Handler(Looper looper, Callback callback) { this(looper, callback, false);}
  public Handler(Looper looper, Callback callback, boolean async) {
        mLooper = looper;
        //获取当前Looper中的MessageQueue
        mQueue = looper.mQueue;
        mCallback = callback;
        mAsynchronous = async;
  }  
 


//handler发送到MessaageQueue(消息队列)中去
//发送及时消息
public final boolean sendMessage(Message msg)
public final boolean sendEmptyMessage(int what)
public final boolean post(Runnable r)
//发送延时消息
public final boolean sendEmptyMessageDelayed(int what, long delayMillis)
public final boolean sendMessageDelayed(Message msg, long delayMillis)
public final boolean postDelayed(Runnable r, long delayMillis)
//发送定时消息
public boolean sendMessageAtTime(Message msg, long uptimeMillis)
public final boolean sendEmptyMessageAtTime(int what, long uptimeMillis)
public final boolean postAtTime(Runnable r, long uptimeMillis)

//所有发送的消息最后都会调用到enqueueMessage
private boolean enqueueMessage(MessageQueue queue,Message msg,long uptimeMillis) {
    //handler 赋值给msg的变量中,最后分发的时候取出该handler进行分发
      msg.target = this;
      msg.workSourceUid = ThreadLocalWorkSource.getUid();
      return queue.enqueueMessage(msg, uptimeMillis);
}

//Looper会调用loop()方法循环的取消息。当取出消息后会调用message.target.dispatchMessage(msg)方法
public void dispatchMessage(Message msg) {
     if (msg.callback != null) {  
        //第一步,判断msg.callback  handler.post()系列方法的时候
         handleCallback(msg);
     } else {
         if (mCallback != null) {
        //第二步、判断Handler的callBack
             if (mCallback.handleMessage(msg)) {
                 return;
             }
         }
         //第三步,执行Handler的handleMessage方法
         handleMessage(msg);
     } 
}

handler.post()系列方法的时候会调用该方法
private static Message getPostMessage(Runnable r) {
      Message m = Message.obtain();
      m.callback = r;
      return m;
 }
private static void handleCallback(Message message) {
      message.callback.run();
   }

handler 问题 https://www.jianshu.com/p/f5722e1e8e6c

上一篇 下一篇

猜你喜欢

热点阅读