Handler的运行机制(个人理解)

一. Handler的主要作用

我们都知道,在android里是不能在子线程里更新UI的, 简单说一下原因: 更新UI时会调用ViewRootImpl.checkThread() 检查当前线程是否与mThread (控件初始化时所在的线程)是否一致,假如不一致,则抛出异常,ViewRootImpl.java关键代码如下:

public ViewRootImpl(Context context, Display display) {
        mThread = Thread.currentThread();
}

void checkThread() {
        if (mThread != Thread.currentThread()) {
            throw new CalledFromWrongThreadException(
                    "Only the original thread that created a view hierarchy can touch its views.");
        }
    }

Handler的主要作用:在子线程中发送消息, 在主线程中更新UI。

二. Handler的基本使用

1. Handler.sendMessage(msg)

    @SuppressLint("HandlerLeak")
    private Handler mHandler = new Handler(){
        @Override
        public void handleMessage(Message msg) {
            super.handleMessage(msg);
            mTextView.setText(msg.obj + ""); //更新UI
        }
    };
  
    //子线程发送消息
    new Thread(new Runnable() {
                @Override
                public void run() {
                    Message message = new Message();
                    message.obj = "6666";
                    mHandler.sendMessage(message);
            }).start();

2. Handler.post(msg)

    @SuppressLint("HandlerLeak")
    private Handler mHandler = new Handler();
  
    //子线程发送消息
    new Thread(new Runnable() {
                @Override
                public void run() {
                   mHandler.post(new Runnable() { //切换到主线程更新UI
                    @Override
                    public void run() { 
                        mTextView.setText("123456");
                    }
                });
            }).start();

二. Handler的运行机制(API28源码解读)

1. Handler.sendMessage(msg)做了些什么?

Handler.java里面的方法(部分关键代码):
sendMessage()→sendMessageDelayed()→sendMessageAtTime()→enqueueMessage;

public final boolean sendMessage(Message msg){
        return sendMessageDelayed(msg, 0);
}
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最终调用了MessageQueue.enqueueMessage()
注意: msg.target = this; msg.target 表示当前对象Handler, 后面Looper.loop()用到

MessageQueue.enqueueMessage()
关键代码如下:

boolean enqueueMessage(Message msg, long when) {
            msg.when = when; 
            Message p = mMessages;
            if (p == null || when == 0 || when < p.when) { 
                  msg.next = p; 
                  mMessages = msg;
             } else {
                  Message prev;
                  for (;;) {
                        prev = p;
                        p = p.next;
                        if (p == null || when < p.when) {
                              break;
                        }
                }
                msg.next = p;
                prev.next = msg;
            }
        }
        return true;
    }

从代码中慢慢分析,我们可以得出结论:其实MessageQueue.enqueueMessage()方法就是把传进来的Message消息对象,按照时间顺序、队列的结构 保存起来。
在这里,我们并没有看到Handler.handleMessage()方法的执行,继续往下看。

2. 从ActivityThread.main()分析

我们就不慢慢从问题引进来了,直奔主题。

 public static void main(String[] args) {
        Looper.prepareMainLooper();  //初始化
        Looper.loop();
    }
2.1.首先我们看Looper.prepareMainLooper()做了些什么

prepareMainLooper()→prepare()

public static void prepareMainLooper() {
        prepare(false);
        synchronized (Looper.class) {
            if (sMainLooper != null) {  //如果进行第二次初始化,则回报异常
                throw new IllegalStateException("The main Looper has already been prepared.");
            }
            sMainLooper = myLooper(); //赋值
        }
    }

//有且只有一个ThreadLocal对象
static final ThreadLocal sThreadLocal = new ThreadLocal(); 

private static void prepare(boolean quitAllowed) {
         //进入ThreadLocal源码里set()和get()可以看出,每个线程只保存一个Looper对象
        //所以每个线程只能调用一次prepare(),否则会抛异常
        if (sThreadLocal.get() != null) {  
            throw new RuntimeException("Only one Looper may be created per thread");
        }
       //ThreadLocal保存Looper对象
        sThreadLocal.set(new Looper(quitAllowed)); 
    }
注意:prepare()方法 这里有2个关键点:

(1) sThreadLocal.set() 和 get()方法
(2) Looper.java构造方法new Looper().

(1). ThreadLocal.java 的set()和get()

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

public void set(T value) {
        Thread t = Thread.currentThread();
        ThreadLocalMap map = getMap(t);
        if (map != null)
            map.set(this, value);
        else
            createMap(t, value);
    }

set():给当前线程赋值一个:Loop对象
get():获取当前线程的Loop对象

(2). Looper.java构造方法

    private Looper(boolean quitAllowed) {
        mQueue = new MessageQueue(quitAllowed);
        mThread = Thread.currentThread();
    }

主要初始化消息队列MessageQueue,即:一个Loop有一个MessageQueue消息队列对象

总结:Looper.prepareMainLooper() 主要作用:
  1. 初始化Looper.sThreadLocal.set(new Loop()当前线程唯一对象)

  2. 初始化 MessageQueue对象, new Loop() 对应一个MessageQueue对象

2.2. Looper.loop();

下面是部分的关键代码

public static void loop() {
        final Looper me = myLooper(); //获取唯一的Loop对象
        if (me == null) {  //假如sThreadLocal.set()没有赋值,则会抛出异常
            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.enqueueMessage() 方法里面可以看出,msg.target就是当前的Handler对象
                msg.target.dispatchMessage(msg);  
            }
            msg.recycleUnchecked();  //资源缓存和回收
        }
    }

public static @Nullable Looper myLooper() {
        return sThreadLocal.get();
}

代码里面都有注释,最核心代码是msg.target.dispatchMessage(msg),msg.target就是当前的Handler对象,
接下来我们来看Handler.dispatchMessage().

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

这里就执行了handleMessage()方法

2.3. 资源回收处理 msg.recycleUnchecked()
 private static int sPoolSize = 0;
 private static final int MAX_POOL_SIZE = 50;

 void recycleUnchecked() {
        flags = FLAG_IN_USE;
        what = 0;
        arg1 = 0;
        arg2 = 0;
        obj = null;
        replyTo = null;
        sendingUid = -1;
        when = 0;
        target = null;
        callback = null;
        data = null;

        synchronized (sPoolSync) {
            if (sPoolSize < MAX_POOL_SIZE) {
                next = sPool;
                sPool = this;
                sPoolSize++;
            }
        }
    }
结论:Msg 对象范围0到50个

最后图解,如下图:


Handler机制原理图.png

三. Handler 常见问题

1. 在子线程中创建Handler对象会抛出异常。

原因:Looper.sThreadLocal.set()没有初始化ThreadLocalMap对象,导致Handler.mLooper = null;

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

解决方法:
1.先执行Looper.prepare()初始化,一个线程只能执行一次。

  1. 创建Handler对象。
  2. Looper.loop(); //开始循环 发送队列消息 ,如果没有这一句,是接收不到消息的。

2. handler.post() 和 sendMessage的区别。

  1. 写法不一样
  2. post()的msg对象是去缓存里面找的,假如缓存没有就创建一个新的msg对象,
    sendMessage的msg对象是从外面传进来的,可以自定义带参数。
 public final boolean post(Runnable r) {
       return  sendMessageDelayed(getPostMessage(r), 0);
 }

你可能感兴趣的:(Handler的运行机制(个人理解))