王学岗移动架构(2)————Android消息机制

android源码在线地址

1,android 消息机制主要是指Handler的运行机制
在这里插入图片描述
发送消息后会通过enqueueMesage 把消息发送到消息队列MessageQueue,Looper会不断的从消息队列中拿出消息,looper是一个线程,当消息队列中没有消息的时候,这个looper线程就会被挂起来。
什么是挂起呢?通俗讲就是不去做它该做的事情。比如老师讲课,学生却不听,那么就是这些学生把老师挂起来了。
2,ThreadLocal的工作原理
定义:ThreadLocal是一个线程内部的数据存储类,通过它可以在指定的线程中存储数据,数据存储以后,只能再指定线程中可以获取到存储的数据,对于其他线程来说则无法获取到数据。
Thread A和Thread B不能拿到对方线程之间的数据
ThreadLocal好比一个钱包,只有自己可以在其中取钱。
看一段代码

  //创建一个本地线程,因为是在单元测试中写的代码,所以我们把它当作主线程
        //ThreadLocal 需要传入一个泛型,
        // ThreadLocal里面有一个内部类ThreadLocalMap,ThreadLocalMap类里有一个键值对,键值对的值就是我们传入的泛型,
        //k是我们当前线程的名字,
        ThreadLocal<String> threadLocal = new ThreadLocal<String>(){
            //初始化的方法
            @Nullable
            @Override
            protected String initialValue() {
                //不调用父类的,我们自己重写,查看源码可以知道,它默认返回的是一个null
//                return super.initialValue();
                return "张欣爱我一生一世";
            }
        };
        //打印输出"张欣爱我一生一世"
        System.out.println(threadLocal.get());

我们分析下以上代码的源码
查看threadLocal.get()源码(源码a)

   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();
    }
    ThreadLocalMap getMap(Thread t) {
        return t.threadLocals;
    }

再看下getMap(t);(源码b)

ThreadLocalMap getMap(Thread t) {
        return t.threadLocals;
    }

返回的是Thread类的threadLocals。
我们再看下Thread类(源码c)
ThreadLocal.ThreadLocalMap threadLocals = null;
在Thread类中也没有对threadLocals赋值
我们返回源码a处
也就是这句代码
ThreadLocalMap map = getMap(t);
map是空,所以会执行
return setInitialValue();
我们点进去看看setInitialValue源码(源码h)

    private T setInitialValue() {
    //调用我们重写的initialValue();我们重写的这个方法返回的是"张欣爱我一生一世"
    //这里的泛型T就是String,这里的value就是"张欣爱我一生一世"
        T value = initialValue();
        //获取当前线程
        Thread t = Thread.currentThread();
        //这里的map依旧是null
        ThreadLocalMap map = getMap(t);
        if (map != null)
            map.set(this, value);
        else
        //执行这句代码
            createMap(t, value);
        return value;
    }

我们看看createMap(t, value);代码的源码(源码i)
ThreadLocal类的该方法源码是

    void createMap(Thread t, T firstValue) {
        t.threadLocals = new ThreadLocalMap(this, firstValue);
    }

在这里我们终于为Thread类的threadLocals赋值了。
经过源码的分析,我们终于知道为什么会返回"张欣爱我一生一世"了;
我们再看一段源码

package com.example.xiaoxijizhi;

import androidx.annotation.Nullable;
import androidx.appcompat.app.AppCompatActivity;

import android.os.Bundle;

public class MainActivity extends AppCompatActivity {

    private ThreadLocal<String> threadLocal;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        //创建一个本地线程,因为是在单元测试中写的代码,所以我们把它当作主线程
        //ThreadLocal 需要传入一个泛型,
        // ThreadLocal里面有一个内部类ThreadLocalMap,ThreadLocalMap类里有一个键值对,键值对的值就是我们传入的泛型,
        //k是我们当前线程的名字,
        threadLocal = new ThreadLocal<String>(){
            //初始化的方法
            @Nullable
            @Override
            protected String initialValue() {
                //不调用父类的,我们自己重写,查看源码可以知道,它默认返回的是一个null
//                return super.initialValue();
                return "张欣爱我一生一世";
            }
        };
        //打印输出"张欣爱我一生一世"
        System.out.println(threadLocal.get());

//        创建一个子线程
        Thread thread = new Thread(new Runnable() {
            @Override
            public void run() {
             String value = threadLocal.get();
                System.out.println(value);//打印输出"张欣爱我一生一世"
                 threadLocal.set("我不爱张欣");
                System.out.println(threadLocal.get());//打印输出"我不爱张欣"
                 //清理线程
                threadLocal.remove();
            }
        });
        thread.start();
    }
}

我们再次查看threadLocal.get();源码(源码a)

    public T get() {
    //得到我们创建的子线程
        Thread t = Thread.currentThread();
        //这里的map依旧为null
        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();
    }

我们看下setInitialValue();源码(源码b)

private T setInitialValue() {
        T value = initialValue();
        Thread t = Thread.currentThread();
        ThreadLocalMap map = getMap(t);
        if (map != null)
            map.set(this, value);
        else
            createMap(t, value);
        return value;
    }

同第一次分析的一模一样。
3,估计有人心里犯嘀咕了,第二部分讲的ThreadLocal跟消息机制有毛关系呢?看官别急,一点一点来。我们下面正式进入主题了。我们从app启动讲解。

(1) app启动的时候做的事情
在这里插入图片描述
我们查看ActivityThread类的main方法

 public static void main(String[] args) {
         Looper.prepareMainLooper();
 }

我们查找Looper.prepareMainLooper();方法源码

 public static void prepareMainLooper() {
115        prepare(false);
116        synchronized (Looper.class) {
117            if (sMainLooper != null) {
118                throw new IllegalStateException("The main Looper has already been prepared.");
119            }
120            sMainLooper = myLooper();
121        }
122    }

继续查看 prepare(false);的源码

   private static void prepare(boolean quitAllowed) {
102        if (sThreadLocal.get() != null) {
103            throw new RuntimeException("Only one Looper may be created per thread");
104        }
105        sThreadLocal.set(new Looper(quitAllowed));
106    }

这里就有ThreadLocal对象,创建了全局唯一的主线程Looper对象
在Looper的构造方法里面创建了全局唯一的MessageQueue对象,同时把线程对象赋值为当前线程,即主线程

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

(2)activity 中创建Handler
在这里插入图片描述
创建Handler的时候会拿到全局唯一的Loop对象( Looper looper = Looper.myLooper() 通过该代码拿到)。拿到Looper对象是在主线程
我们看一段代码

package com.example.xiaoxijizhi;

import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import androidx.appcompat.app.AppCompatActivity;

import android.os.Bundle;
import android.os.Handler;
import android.os.Message;
import android.util.Log;
import android.view.View;

public class MainActivity extends AppCompatActivity {

    private Handler handler = new Handler(){
        @Override
        public void handleMessage(@NonNull Message msg) {
            super.handleMessage(msg);
            //打印输出1
            Log.i("zhang_xin",msg.what+"");
        }
    };

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
    }

    public void click(View view) {
        new Thread(new Runnable() {
            @Override
            public void run() {
                Message message = new Message();
                message.what = 1;
                handler.sendMessage(message);
            }
        }).start();
    }
}

非常简单的一段代码,我们在源码中查看它是如何运行的。
我们从创建Handler开始,查看new Handler()源码

  public Handler() {
        this(null, 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()");
        }
        //从Looper对象中得到全局唯一的MessageQueue对象
        mQueue = mLooper.mQueue;
        mCallback = callback;
        mAsynchronous = async;
    }

我们在查看 mLooper = Looper.myLooper();源码

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

从sThreadLocal中得到Looper对象。
(3)消息发送
在这里插入图片描述
messag.target=this 把message赋值给handler(target就是handler)
我们看下 handler.sendMessage(message);的源码
追踪源码可以发现Handler类如下代码

public boolean sendMessageAtTime(@NonNull Message msg, long uptimeMillis) {
       //把全局唯一的消息队列,赋值给局部变量
        MessageQueue queue = mQueue;
        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);
    }

我们继续追踪enqueueMessage(queue, msg, uptimeMillis);源码,依然是在Handler类

 private boolean enqueueMessage(@NonNull MessageQueue queue, @NonNull Message msg,
            long uptimeMillis) {
            //注意这个target,是一个Handler类对象,这里把我们的Handler赋值到Message的target中
        msg.target = this;
        msg.workSourceUid = ThreadLocalWorkSource.getUid();

        if (mAsynchronous) {
            msg.setAsynchronous(true);
        }
        return queue.enqueueMessage(msg, uptimeMillis);
    }

我们点进去msg.target,会发现他是Message类的一个成员变量,
Handler.target
我们在进入这个句代码看下 queue.enqueueMessage(msg, uptimeMillis);它的源码。源码在MessageQueue里

 boolean enqueueMessage(Message msg, long when) {
        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;
            boolean needWake;
            if (p == null || when == 0 || when < p.when) {
                // New head, wake up the event queue if blocked.
                msg.next = p;
                //这里把我们的消息赋值给MessageQueue中的全局变量,然后把消息放到了消息对列中
                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;
            }

            // We can assume mPtr != 0 because mQuitting is false.
            if (needWake) {
                nativeWake(mPtr);
            }
        }
        return true;
    }

(4)消息处理
在这里插入图片描述
ThreadActivity类的main方法中,会有这句代码
Looper.loop()这句代码就是开启循环,我们点进去看下。

    public static void loop() {
    //拿到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(); // might block
            if (msg == null) {
                // No message indicates that the message queue is quitting.
                return;
            }
               //调用Handler的dispatchMessage方法
                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 (slowDeliveryDetected) {
                    if ((dispatchStart - msg.when) <= 10) {
                        Slog.w(TAG, "Drained");
                        slowDeliveryDetected = false;
                    }
                } else {
                    if (showSlowLog(slowDeliveryThresholdMs, msg.when, dispatchStart, "delivery",
                            msg)) {
                        // Once we write a slow delivery log, suppress until the queue drains.
                        slowDeliveryDetected = 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();
        }
    }

我们看下Handler的dispatchMessage()做了什么

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

这里会执行handlerMessage(msg)方法。
我们看下Handler的handlerMessage(msg)方法,会发现它是一个空方法,具体实现我们可以自己定义

 public void handleMessage(@NonNull Message msg) {
    }

4,消息的阻塞,唤醒,延时入队
(1)Looper 的阻塞主要是靠 MessageQueue 来实现的,在next()@MessageQuese 进行阻塞(阻塞不会卡),在 enqueueMessage()@MessageQueue 进行唤醒(有阻塞就有唤醒,阻塞和唤醒都是native方法)。主要依赖 native 层的 Looper 依靠 epoll 机制进行的。
(2)阻塞的native方法
nativePollOnce(ptr, nextPollTimeoutMillis);
这里调用naive方法操作管道,由nextPollTimeoutMillis决定是否需要阻塞
nextPollTimeoutMillis为0的时候表示不阻塞,为-1的时候表示一直阻塞直到被唤醒。
阻塞的时候native里会做一些资源的释放,所以主线程不会被卡死
(3)第一条消息延迟的发送(延迟入队),就是该消息阻塞固定时间(小于Integer.MaxValue)。
第二条消息假如不延迟发送,会把该次发送的时间与上次发送的时间做比较,如果这次消息早于上次发送的消息,就把上一条消息标记为下一条消息,把当前消息赋值为全局消息,然后唤醒。(可以理解为在Message对象池中把消息按照时间排序)
(4)Message对象池最多可以存放50message消息。
(5)

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值