首页
搜索 搜索
当前位置:商业资讯 > 正文

全球信息:我所知道的Handler

2023-05-18 06:27:09 博客园

简单讲,handler就是两个功能

插入消息,enqueuemessage,msg,when从消息队列中遍历所有消息,比对msg.when和当前的when,找到合适的位置插入

处理消息,looper.loop会从messagequeue中调用next。取消息,如果消息还没到时间该执行,就会比对时间,下次轮询就通过binder写入,native函数休眠,到时间唤醒执行。


(资料图片仅供参考)

handler内存泄漏

GCRoot 一般是静态变量或者常量可以作为GCROOTGCROOT 是ThreadLocal,存在于Looper中,Looper被加载就存在,handler持有activity或者fragment,handler又被message持有,message的target属性,message被messagequeue持有,messagequeue被looper中的threadlocal持有

java中匿名内部类会默认持有外部类的引用

打断持有链

  1. handler.removemesage handler.removecallbacks
  2. handler使用static修饰。

主线程的Looper不允许退出

处理消息,looper取出来后,调用message.tager.dispatchemesage后面调用了handler的handlemessage方法。

还有个callback对象,如果有callback,dispatch会先执行callback的处理,calllback返回true,后面就不处理了,callback返回false就给handler的handlemessage处理了

Meesage对象创建

message创建用的obtain,池化,频繁的创建销毁会导致内存不稳定,抖动,造成卡顿 oom等问题

message pool的最大缓存50

阻塞和休眠,阻塞是被动的,休眠是主动的,阻塞不会让出cpu,休眠会,thread.yield会让出cpu。

子线程主线程通信

handler,livedata,eventbus,flow,rxjava,broadcast,观察者模式不能跨线程

最终都是handler完成的。

Handler监听卡顿

原理是在looper内完成的,looper处理消息的时候,会打印内容,就是Printer,looper可以设置它。

Message消息的分类

同步消息,普通的消息都是同步消息异步消息,创建handler的时候设置async为true即可同步屏障,需要通过反射调用,app层无法直接调用,是messagequeue提供的posSyncBarrier方法实现的,返回一个token,时msg的arg1值,用它来取消同步屏障。和普通消息的区别是,msg。target属性为null。

刷新UI的消息是异步消息,发送前先插入了一个同步屏障消息,异步消息处理完成后,要将同步屏障消息移除队列

消息入队

handler消息加入队列,有一系列方法,如下:

// 发送空消息public final boolean sendEmptyMessage(int what){}public final boolean sendEmptyMessageDelayed(int what,long delay){}public final boolean sendEmptyMessageAtTime(int what,long when){}// 发送消息public final boolean sendMessage(@NonNull Message msg){}public final boolean sendMessageDelayed(@NonNull Message msg,long time){}public final boolean sendMessageAtTime(@NonNull Message msg,long when){}public final boolean sendMessageAtFrontOfQueue(Message msg) {}// post发送public final boolean post(@NonNull Runnable r) {}public final boolean postAtTime(@NonNull Runnable r, long uptimeMillis) {}public final boolean postAtTime(  @NonNull Runnable r, @Nullable Object token, long uptimeMillis) {}public final boolean postDelayed(@NonNull Runnable r, long delayMillis) {}public final boolean postDelayed(Runnable r, int what, long delayMillis) {}public final boolean postDelayed(          @NonNull Runnable r, @Nullable Object token, long delayMillis) {}public final boolean postAtFrontOfQueue(@NonNull Runnable r) {}// enqueuepublic final boolean executeOrSendMessage(@NonNull Message msg) {}private boolean enqueueMessage(@NonNull MessageQueue queue, @NonNull Message msg,          long uptimeMillis) {}

最终都是掉用的enqueueMessage加入队列

private boolean enqueueMessage(@NonNull MessageQueue queue, @NonNull Message msg,          long uptimeMillis) {      msg.target = this;  // 绑定消息处理对象    msg.workSourceUid = ThreadLocalWorkSource.getUid();        if (mAsynchronous) { // 根据handler创建是否是异步的,来将消息标记为异步消息         msg.setAsynchronous(true);      }      // 调用messagequeue的方法,加入队列。    return queue.enqueueMessage(msg, uptimeMillis);  }

下面看下消息如何入队的

boolean enqueueMessage(Message msg, long when) {      if (msg.target == null) {          throw new IllegalArgumentException("Message must have a target.");      }        synchronized (this) {          if (msg.isInUse()) {              throw new IllegalStateException(msg + " This message is already in use.");          }            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.              // 消息队列为null,或者消息是立刻执行的,或者要执行的时间先于头消息的时间,将当前消息作为新的队列的头            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;          }  // 如果需要的话,唤醒队列,开始处理消息,就是MessageQueue的next方法开始执行        // We can assume mPtr != 0 because mQuitting is false.          if (needWake) {              nativeWake(mPtr);          }      }      return true;  }

取消息以及消息处理

取消息1

取消息入口是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.");      }      if (me.mInLoop) {          Slog.w(TAG, "Loop again would have the queued messages be executed"                  + " before this one completed.");      }        me.mInLoop = true;        // Make sure the identity of this thread is that of the local process,      // and keep track of what that identity token actually is.    Binder.clearCallingIdentity();      final long ident = Binder.clearCallingIdentity();        // Allow overriding a threshold with a system prop. e.g.      // adb shell "setprop log.looper.1000.main.slow 1 && stop && start"    final int thresholdOverride =              SystemProperties.getInt("log.looper."                      + Process.myUid() + "."                      + Thread.currentThread().getName()                      + ".slow", 0);        me.mSlowDeliveryDetected = false;  // 无限循环,通过loopOnce取消息    for (;;) {          if (!loopOnce(me, ident, thresholdOverride)) {              return;          }      }  }

处理消息

private static boolean loopOnce(final Looper me,          final long ident, final int thresholdOverride) {      // 取消息    Message msg = me.mQueue.next(); // might block      if (msg == null) {          // No message indicates that the message queue is quitting.          return false;      }        // This must be in a local variable, in case a UI event sets the logger      final Printer logging = me.mLogging;      if (logging != null) {          logging.println(">>>>> Dispatching to " + msg.target + " "                  + msg.callback + ": " + msg.what);      }      // Make sure the observer won"t change while processing a transaction.      final Observer observer = sObserver;        final long traceTag = me.mTraceTag;      long slowDispatchThresholdMs = me.mSlowDispatchThresholdMs;      long slowDeliveryThresholdMs = me.mSlowDeliveryThresholdMs;      if (thresholdOverride > 0) {          slowDispatchThresholdMs = thresholdOverride;          slowDeliveryThresholdMs = thresholdOverride;      }      final boolean logSlowDelivery = (slowDeliveryThresholdMs > 0) && (msg.when > 0);      final boolean logSlowDispatch = (slowDispatchThresholdMs > 0);        final boolean needStartTime = logSlowDelivery || logSlowDispatch;      final boolean needEndTime = logSlowDispatch;        if (traceTag != 0 && Trace.isTagEnabled(traceTag)) {          Trace.traceBegin(traceTag, msg.target.getTraceName(msg));      }        final long dispatchStart = needStartTime ? SystemClock.uptimeMillis() : 0;      final long dispatchEnd;      Object token = null;      if (observer != null) {          token = observer.messageDispatchStarting();      }      long origWorkSource = ThreadLocalWorkSource.setUid(msg.workSourceUid);      try {      // 这里取出msg的target属性,就是handler对象,进行消息的处理。注意:屏障消息是没有target的。        msg.target.dispatchMessage(msg);          if (observer != null) {              observer.messageDispatched(token, msg);          }          dispatchEnd = needEndTime ? SystemClock.uptimeMillis() : 0;      } catch (Exception exception) {          if (observer != null) {              observer.dispatchingThrewException(token, msg, exception);          }          throw exception;      } finally {          ThreadLocalWorkSource.restore(origWorkSource);          if (traceTag != 0) {              Trace.traceEnd(traceTag);          }      }      if (logSlowDelivery) {          if (me.mSlowDeliveryDetected) {              if ((dispatchStart - msg.when) <= 10) {                  Slog.w(TAG, "Drained");                  me.mSlowDeliveryDetected = false;              }          } else {              if (showSlowLog(slowDeliveryThresholdMs, msg.when, dispatchStart, "delivery",                      msg)) {                  // Once we write a slow delivery log, suppress until the queue drains.                  me.mSlowDeliveryDetected = true;              }          }      }      // 这里会打印那些执行慢的消息    if (logSlowDispatch) {          showSlowLog(slowDispatchThresholdMs, dispatchStart, dispatchEnd, "dispatch", msg);      }        if (logging != null) {          logging.println("<<<<< Finished to " + msg.target + " " + msg.callback);      }        // Make sure that during the course of dispatching the      // identity of the thread wasn"t corrupted.    final long newIdent = Binder.clearCallingIdentity();      if (ident != newIdent) {          Log.wtf(TAG, "Thread identity changed from 0x"                  + Long.toHexString(ident) + " to 0x"                  + Long.toHexString(newIdent) + " while dispatching to "                  + msg.target.getClass().getName() + " "                  + msg.callback + " what=" + msg.what);      }        msg.recycleUnchecked();        return true;  }

取消息2

再看下实际的取消息的方法,MessageQueue的next方法

Message next() {      // Return here if the message loop has already quit and been disposed.      // This can happen if the application tries to restart a looper after quit    // which is not supported.        final long ptr = mPtr;      if (ptr == 0) {          return null;      }        int pendingIdleHandlerCount = -1; // -1 only during first iteration      int nextPollTimeoutMillis = 0;      for (;;) {          if (nextPollTimeoutMillis != 0) {              Binder.flushPendingCommands();          }  // 这个方法会在没有消息的时候阻塞        nativePollOnce(ptr, nextPollTimeoutMillis);            synchronized (this) {              // Try to retrieve the next message.  Return if found.              final long now = SystemClock.uptimeMillis();              Message prevMsg = null;            // 消息头保存            Message msg = mMessages;              if (msg != null && msg.target == null) {                  // Stalled by a barrier.  Find the next asynchronous message in the queue.                  // 这里处理同步屏障消息,如果当前消息是异步消息,就跳出循环,否则继续循环                do {                      prevMsg = msg;                      msg = msg.next;                  } while (msg != null && !msg.isAsynchronous());                 // 循环的作用,找出队列里的异步消息,存储在msg里,或者将同步屏障消息存储在msg中,prevMsg存储的是同步消息             }              if (msg != null) {                  if (now < msg.when) {                  // 下次的唤醒时间                    // Next message is not ready.  Set a timeout to wake up when it is ready.                      nextPollTimeoutMillis = (int) Math.min(msg.when - now, Integer.MAX_VALUE);                  } else {                      // Got a message.                      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();                     // 将取出的消息交给handler处理。                     return msg;                  }              } else {                  // No more messages.                  nextPollTimeoutMillis = -1;              }                // Process the quit message now that all pending messages have been handled.              if (mQuitting) {                  dispose();                  return null;              }                // If first time idle, then get the number of idlers to run.              // Idle handles only run if the queue is empty or if the first message            // in the queue (possibly a barrier) is due to be handled in the future.                        if (pendingIdleHandlerCount < 0                      && (mMessages == null || now < mMessages.when)) {                  pendingIdleHandlerCount = mIdleHandlers.size();              }              if (pendingIdleHandlerCount <= 0) {                  // No idle handlers to run.  Loop and wait some more.                  mBlocked = true;                  continue;              }                if (mPendingIdleHandlers == null) {                  mPendingIdleHandlers = new IdleHandler[Math.max(pendingIdleHandlerCount, 4)];              }              mPendingIdleHandlers = mIdleHandlers.toArray(mPendingIdleHandlers);          }            // Run the idle handlers.          // We only ever reach this code block during the first iteration.                for (int i = 0; i < pendingIdleHandlerCount; i++) {              final IdleHandler idler = mPendingIdleHandlers[i];              mPendingIdleHandlers[i] = null; // release the reference to the handler                boolean keep = false;              try {                  keep = idler.queueIdle();              } catch (Throwable t) {                  Log.wtf(TAG, "IdleHandler threw exception", t);              }                if (!keep) {                  synchronized (this) {                      mIdleHandlers.remove(idler);                  }              }          }            // Reset the idle handler count to 0 so we do not run them again.          pendingIdleHandlerCount = 0;            // While calling an idle handler, a new message could have been delivered          // so go back and look again for a pending message without waiting.                nextPollTimeoutMillis = 0;      }  }

handler的消息处理

是从dispatchMessage方法开始的,里面进行消息处理

public void dispatchMessage(@NonNull Message msg) {// 检查message是否设置了callback对象(runnable类型的)if (msg.callback != null) {// 执行其run方法handleCallback(msg);} else {// 检查handler是否设置了callback对象if (mCallback != null) {if (mCallback.handleMessage(msg)) {// 如果返回true,后续就不执行了。return;}}// 自定义handler的时候,实现该方法处理消息handleMessage(msg);}}

IdleHandler是什么?干什么?继续看MessageQueue类。

IdleHandler是MessageQueue的静态内部接口。如下

public static interface IdleHandler {      /**       * Called when the message queue has run out of messages and will now     * wait for more.  Return true to keep your idle handler active, false     * to have it removed.  This may be called if there are still messages     * pending in the queue, but they are all scheduled to be dispatched     * after the current time.     */            boolean queueIdle();  }

当前线程的消息对立内当前没有消息要处理时,会取出idlehander执行任务,因为执行在主线程,禁止执行耗时操作。返回true表示执行完并不会移除该对象,false执行完一次就移除。而且,执行时机是不确定的。执行的地方在next方法内部。

Message next() {      // Return here if the message loop has already quit and been disposed.      // This can happen if the application tries to restart a looper after quit    // which is not supported.       final long ptr = mPtr;      if (ptr == 0) {          return null;      }        int pendingIdleHandlerCount = -1; // -1 only during first iteration      int nextPollTimeoutMillis = 0;      for (;;) {          if (nextPollTimeoutMillis != 0) {              Binder.flushPendingCommands();          }            nativePollOnce(ptr, nextPollTimeoutMillis);            synchronized (this) {              // Try to retrieve the next message.  Return if found.              final long now = SystemClock.uptimeMillis();              Message prevMsg = null;              Message msg = mMessages;              if (msg != null && msg.target == null) {                  // Stalled by a barrier.  Find the next asynchronous message in the queue.                  do {                      prevMsg = msg;                      msg = msg.next;                  } while (msg != null && !msg.isAsynchronous());              }              if (msg != null) {                  if (now < msg.when) {                      // Next message is not ready.  Set a timeout to wake up when it is ready.                      nextPollTimeoutMillis = (int) Math.min(msg.when - now, Integer.MAX_VALUE);                  } else {                      // Got a message.                      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;              }                // Process the quit message now that all pending messages have been handled.              if (mQuitting) {                  dispose();                  return null;              }  // 执行到这里,说明没有找到message对象需要执行了,且线程没有退出。            // If first time idle, then get the number of idlers to run.              // Idle handles only run if the queue is empty or if the first message            // in the queue (possibly a barrier) is due to be handled in the future.                        if (pendingIdleHandlerCount < 0                      && (mMessages == null || now < mMessages.when)) {                  pendingIdleHandlerCount = mIdleHandlers.size();              }              if (pendingIdleHandlerCount <= 0) {                  // No idle handlers to run.  Loop and wait some more.                  mBlocked = true;                  continue;              }  // 取出idlehandlers            if (mPendingIdleHandlers == null) {                  mPendingIdleHandlers = new IdleHandler[Math.max(pendingIdleHandlerCount, 4)];              }              mPendingIdleHandlers = mIdleHandlers.toArray(mPendingIdleHandlers);          }            // Run the idle handlers.          // We only ever reach this code block during the first iteration.          for (int i = 0; i < pendingIdleHandlerCount; i++) {              final IdleHandler idler = mPendingIdleHandlers[i];              mPendingIdleHandlers[i] = null; // release the reference to the handler                boolean keep = false;              try {              // 执行idlehandler的方法                keep = idler.queueIdle();              } catch (Throwable t) {                  Log.wtf(TAG, "IdleHandler threw exception", t);              }                if (!keep) {             // 需要移除的话,在此处进行移除                synchronized (this) {                      mIdleHandlers.remove(idler);                  }              }          }            // Reset the idle handler count to 0 so we do not run them again.          pendingIdleHandlerCount = 0;            // While calling an idle handler, a new message could have been delivered          // so go back and look again for a pending message without waiting.                  nextPollTimeoutMillis = 0;      }  }