美文网首页
安卓源码-handler源码分析

安卓源码-handler源码分析

作者: isLJli | 来源:发表于2020-06-27 11:06 被阅读0次

先写一个简单的子线程调用Handler的方式:

private  Handler handler = new Handler(){
      @Override
      public void handleMessage(@NonNull Message msg) {
          super.handleMessage(msg);
          mTxt.setText(msg.obj.toString());
      }
  };


  @Override
  protected void onCreate(Bundle savedInstanceState) {
      super.onCreate(savedInstanceState);
      setContentView(R.layout.activity_main);
      mTxt= findViewById(R.id.txt);
      new Thread(new Runnable() {
          @Override
          public void run() {
              try {
                  Thread.sleep(1000);
              } catch (InterruptedException e) {
                  e.printStackTrace();
              }

              Message message = Message.obtain();
              message.obj="123456";
              handler.sendMessage(message);
          }
      });
}}

我们从handler.sendMessage(Message)看起
先总结一下,再详细分析:handler.sendMessage()这个方法只是将message在messageQueue中按执行时间的先后形成一个单链表,只是一个存储message操作:

#Handler
public final boolean sendMessage(@NonNull Message msg) {
      return sendMessageDelayed(msg, 0);
  }

public final boolean sendMessageDelayed(@NonNull Message msg, long delayMillis) {
      if (delayMillis < 0) {
          delayMillis = 0;
      }
      return sendMessageAtTime(msg, SystemClock.uptimeMillis() + delayMillis);
  }

public boolean sendMessageAtTime(@NonNull Message msg, long uptimeMillis) {
      MessageQueue queue = mQueue;//这个Queue在Looper中拿到,后面会讲
      if (queue == null) {
          RuntimeException e = new RuntimeException(
                  this + " sendMessageAtTime() called with no mQueue");
          Log.w("Looper", e.getMessage(), e);
          return false;
      }
      return enqueueMessage(queue, msg, uptimeMillis);
  }

private boolean enqueueMessage(@NonNull MessageQueue queue, @NonNull Message msg,
          long uptimeMillis) {
     //可以看到msg.target就是对应的Handler
      msg.target = this;
      msg.workSourceUid = ThreadLocalWorkSource.getUid();

      if (mAsynchronous) {
          msg.setAsynchronous(true);
      }
     //这里开始调用MessageQueue的enqueueMessage方法把message存成单链表
      return queue.enqueueMessage(msg, uptimeMillis);
  }

我们看看messageQueue的enqueusMessage如何按执行时间存储message成单链表?

#MessageQueue
boolean enqueueMessage(Message msg, long when) {
      // 判断有没有 target 
      if (msg.target == null) {
          throw new IllegalArgumentException("Message must have a target.");
      }
      // 有没有在使用 
      if (msg.isInUse()) {
          throw new IllegalStateException(msg + " This message is already in use.");
      }
      // 对当前消息队列加锁。
      synchronized (this) {
          // 判断消息队列是否弃用(通常因为线程已死)
          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; //这个是拿到表头,第一次是null
          boolean needWake;
          // 第一次添加数据到队列中,或者当前 msg 的时间=0,或者小于表头msg的时间,就将此msg放在前面
          if (p == null || when == 0 || when < p.when) {
              // New head, wake up the event queue if blocked.
              // 把当前 msg 添加到链表的第一个
              msg.next = p;
              mMessages = msg;
              needWake = mBlocked;
          } else {
              // 不是第一次添加数据,并且 msg 的时间 大于 mMessages(头指针) 的时间
              // 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;
                  //知道找到链表最后一个元素或者时间比它大的时候break,所以也不是死循环
                  if (p == null || when < p.when) {
                      break;
                  }
                  if (needWake && p.isAsynchronous()) {
                      needWake = false;
                  }
              }
              //跳出循环后,
              // 把当前 msg 插入到列表中
              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;
  }

文字总结:MessageQueue的enqueueMessage()方法就是将发送过来的信息按执行的时间顺序排一个单链表。

Handler的创建

上面的sendMessage()只是存储message,不做任何的操作,我们知道handler主要作用是切换到主线程更新UI,所以我们继续探索handler的创建。

handler的创建有两种,一种是直接在主线程创建,一种是在子线程种创建,但是在子线程中创建,要在前面加Looper.prepare()和在后面添加Looper.loop()。那么为什么主线中就不用呢?我们来分析分析。

//主线程中创建handler
private  Handler handler = new Handler(){
      @Override
      public void handleMessage(@NonNull Message msg) {
          super.handleMessage(msg);
          mTxt.setText(msg.obj.toString());
      }
  };
new Thread(new Runnable() {
          @Override
          public void run() {
              Message message = Message.obtain();
              message.obj="123456";
              handler.sendMessage(message);
          }
      }).start();

//子线程中创建handler
new Thread(){
  @Override
  public void run() {
     //作用是每一个线程绑定一个Looper
      Looper.prepare();
      Handler handler = new Handler();
    //作用是获得当前线程的Looper,然后拿到这个Looper的MessageQueue,之后遍历MesQueue拿到message,然后调用message的traget就是Handler调用dispatchMessage(方法)。
      Looper.loop(); 
  }
}.start();

主线程不用写Looper.perpare、loop代码,是因为在activity启动的时候,ActvityThread类已经实现了Looper的prepare和loop方法

public static void main(String[] args) {
  // ... 省略部分代码
  
  Looper.prepareMainLooper();

  ActivityThread thread = new ActivityThread();
  thread.attach(false);

  if (sMainThreadHandler == null) {
      sMainThreadHandler = thread.getHandler();
  }

  Looper.loop();

  throw new RuntimeException("Main thread loop unexpectedly exited");
}

现在我们来看看Looper类的prepare()、loop()方法:

#Looper
//创建一个全局唯一ThreadLocal对象
static final ThreadLocal<Looper> sThreadLocal = new ThreadLocal<Looper>();

public static void prepareMainLooper() {
     //调用prepare();
      prepare(false);
      synchronized (Looper.class) {
          if (sMainLooper != null) {
              throw new IllegalStateException("The main Looper has already been prepared.");
          }
          //拿到主线程关联的Looper
          sMainLooper = myLooper();
      }
  }

private static void prepare(boolean quitAllowed) {
      //先判断是否能在当前线程拿到Looper,来看是否创建
      if (sThreadLocal.get() != null) {
          throw new RuntimeException("Only one Looper may be created per thread");
      }
     //在当前线程绑定唯一Looper
      sThreadLocal.set(new Looper(quitAllowed));
  }


#ThreadLocal

public void set(T value) {
      //获取当前线程
      Thread t = Thread.currentThread();
      //拿到当前线程的ThreadLocalMap
      ThreadLocalMap map = getMap(t);
      if (map != null)
          //在map中存储传进来的value,this是调用sThreadLocal
          map.set(this, value);
      else
          createMap(t, value);
  }


ThreadLocalMap getMap(Thread t) {
      //返回当前线程的ThreadLocalMap
      return t.threadLocals;
  }

文字总结:Looper.perpare()方法主要是通过ThreadLocal类的set()方法拿到当前线程的一个ThreadLocalmap来存储Looper,以此来达到一个线程绑定一个Looper。
看看Looper.loop()

#Looper
public static void loop() {
 //获得当前类的Looper
 1. final Looper me = myLooper();
 //从Looper中拿到MessageQueue
  2.final MessageQueue queue = me.mQueue;
  // 一个死循环
  for (;;) {
      // 不断的从消息队列里面取消息
     3. Message msg = queue.next(); // might block
      if (msg == null) {
          // No message indicates that the message queue is quitting.
          return;
      }

      try {
          // 通过 target 去 dispatchMessage 而 target 就是绑定的 Handler
         4. msg.target.dispatchMessage(msg);
      }
          // 消息回收循环利用
         5. msg.recycleUnchecked();
  }
}


//1.获取当前线程的Looper
public static @Nullable Looper myLooper() {
      return sThreadLocal.get();
  }
#ThreadLocal类
//获取当前线程的Looper
public T get() {
      Thread t = Thread.currentThread();
      ThreadLocalMap map = getMap(t);
      if (map != null) {
          ThreadLocalMap.Entry e = map.getEntry(this);
          if (e != null) {
              @SuppressWarnings("unchecked")
              T result = (T)e.value;
              return result;
          }
      }
      return setInitialValue();
  }


2.从Looper获取MessageQuesue
#Looper
private Looper(boolean quitAllowed) {
      mQueue = new MessageQueue(quitAllowed);
      mThread = Thread.currentThread();
  }

//3.在MessageQueue遍历单链表拿到所有msg
Message next() {
  for (;;) {
      synchronized (this) {
          // Try to retrieve the next message.  Return
          final long now = SystemClock.uptimeMillis();
          Message prevMsg = null;
          Message msg = mMessages;
          if (msg != null && msg.target == null) {
              // Stalled by a barrier.  Find the next 
              do {
                  prevMsg = msg;
                  msg = msg.next;
              } while (msg != null && !msg.isAsynchron
          }
          if (msg != null) {
              if (now < msg.when) {
                  // Next message is not ready.  Set a
                  nextPollTimeoutMillis = (int) Math.m
              } 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 mes
                  msg.markInUse();
                  return msg;
              }
          }   
  }

4.执行Handler的dispatchMessage()在下面分析:

看看Handler类

public Handler() {
      this(null, false);
  }
public Handler(@Nullable Callback callback) {
      this(callback, false);
  }
//可以指定在主线程的Looper,Handler就是在主线程中创建。
public Handler(@NonNull Looper looper) {
      this(looper, null, false);
  }
public Handler(@NonNull Looper looper, @Nullable Callback callback) {
      this(looper, callback, false);
  }

public Handler(@Nullable Callback callback, boolean async) {
      if (FIND_POTENTIAL_LEAKS) {
          final Class<? extends Handler> klass = getClass();
          if ((klass.isAnonymousClass() || klass.isMemberClass() || klass.isLocalClass()) &&
                  (klass.getModifiers() & Modifier.STATIC) == 0) {
              Log.w(TAG, "The following Handler class should be static or leaks might occur: " +
                  klass.getCanonicalName());
          }
      }
      //在创建handler之前,就已经有绑定线程的Looper,所以直接拿
      mLooper = Looper.myLooper();
      if (mLooper == null) {
          throw new RuntimeException(
              "Can't create handler inside thread " + Thread.currentThread()
                      + " that has not called Looper.prepare()");
      }
      mQueue = mLooper.mQueue;
      mCallback = callback;
      mAsynchronous = async;
  }
public Handler(@NonNull Looper looper, @Nullable Callback callback, boolean async) {
      mLooper = looper;
      mQueue = looper.mQueue;
      mCallback = callback;
      mAsynchronous = async;
  }


public interface Callback {
      boolean handleMessage(@NonNull Message msg);
  }
  
public void handleMessage(@NonNull Message msg) {
  }

4.执行Handler的dispatchMessage()
public void dispatchMessage(@NonNull Message msg) {
      if (msg.callback != null) {
          handleCallback(msg);
      } else {
          if (mCallback != null) {
              //执行Handler接口mCallback的handleMessage方法
              if (mCallback.handleMessage(msg)) {
                  return;
              }
          }
          执行handler的handleMessage方法
          handleMessage(msg);
      }
  }

//执行msg的callback接口实例的run方法
private static void handleCallback(Message message) {
      message.callback.run();
  }

再看看Message类:

//直接new Message()就是创建一个Message
public Message() {
  }

//如果调用的是Message.obtain()则是从线程池中拿一个message返回。
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();
  }

//这里传进来一个Handler和Runnable会在distachmessage中执行Runnable。
public static Message obtain(Handler h, Runnable callback) {
      Message m = obtain();
      m.target = h;
      m.callback = callback;

      return m;
  }



5.执行消息回收
void recycleUnchecked() {
      // Mark the message as in use while it remains in the recycled object pool.
      // Clear out all other details.
      flags = FLAG_IN_USE;
      what = 0;
      arg1 = 0;
      arg2 = 0;
      obj = null;
      replyTo = null;
      sendingUid = UID_NONE;
      workSourceUid = UID_NONE;
      when = 0;
      target = null;
      callback = null;
      data = null;

      synchronized (sPoolSync) {
          if (sPoolSize < MAX_POOL_SIZE) {
              next = sPool;
              sPool = this;
              sPoolSize++;
          }
      }
  }

总结:

  • Handler在创建之前会有一个Looper绑定当前的线程,所以在创建Handler的时候就可以拿到Looper和MessageQueue。之后调用loop()方法,拿到当前的线程的looper和messageQueue,然后遍历调用单链表message,并拿到message的handler来执行distachMessage()方法,此方法会先判断msg有没有callback(runnable),然后执行这个runnable的run方法,在判断handler是否有callback接口实例,然后执行里面的handlerMessage方法,并return.最后在执行handler本身的handelMessage()方法。

  • handler的sendMessage(msg),会调用sendMessageDelay()方法确定message发送的时间,然后调用MessageQueue的enqueueMessage()方法,把message按执行时间从小到大排成一个单链表。

Handler是怎么导致内存泄漏?(JVM,垃圾检测)

在java中非静态内部类和匿名内部类都会隐式持有当前类的外部引用,由于Handler是非静态内部类所以其持有当前Activity的隐式引用,如果Handler没有被释放,其所持有的外部引用也就是Activity也不可能被释放,导致activtiy被回收不了。
正确写法:

private static class MyHandler extends Handler{
      //持有弱引用HandlerActivity,GC回收时会被回收掉.
      private final WeakReference<HandlerActivity> mActivty;
      public MyHandler(HandlerActivity activity){
          mActivty =new WeakReference<HandlerActivity>(activity);
      }
      @Override
      public void handleMessage(Message msg) {
          HandlerActivity activity=mActivty.get();
          super.handleMessage(msg);
          if(activity!=null){
              //执行业务逻辑
          }
      }
  }

为什么强引用会造成内存泄漏?
答:因为强引用造成JVM的垃圾回收器也不能回收。(直接new出来的对象)
补:弱引用Jvm的垃圾回收器可以回收。

如何判断是否被回收?
根搜索法,Root根开始搜索形成一个环。不在环之内就会被收回。JVM与垃圾回收

class怎么校验的?class字节码的具体内容

相关文章

网友评论

      本文标题:安卓源码-handler源码分析

      本文链接:https://www.haomeiwen.com/subject/rhlqvhtx.html