Android进阶(10)| Android的消息机制

本节目录

一.Android消息机制概述

概念:Android消息机制主要是指Handler的运行机制以及Handler所附带的MessageQueue和Looper的工作过程。

Handler的概念:Handler是Android消息机制中最主要的运行机制,之所以Android系统会引入Handler,主要原因就是为了解决在子线程中无法访问UI的矛盾。

Android系统为什么不允许在子线程中访问UI?
主要原因就是Android的UI空间并不是线程安全的,如果在多线程中并发访问可能会导致UI控件处于不可预期的状态。而如果系统对UI控件的访问加上锁机制,则会大大降低UI访问的效率。因此就引入了Handler。

Handler的工作流程:当Handler被创建完毕后,如果它的send()方法被调用,则它首先会去调用MessageQueue的enqueueMessage()方法并且将这个方法放入消息队列中,然后Looper发现又新消息到来时,就会去处理这个消息,最终消息中的Runnable或者Handler的handleMessage()方法就会被调用。

二.Android消息机制分析

1.ThreadLocal的工作原理

概念:ThreadLocal是一个线程内部的数据存储类,通过它可以在指定的线程中存储数据,数据存储以后,只能够在指定线程中获取到存储的数据,对于其他线程来说则无法获取到数据。

ThreadLocal的内部实现:ThreadLocal是一个泛型类,它的定义为public class ThreadLocal,而它内部主要是又set()和get()方法组成。

  • set方法
public void set(T value){
    Thread currentThread = Thread.currentThread();
    Vlaues values = values(currentThread);
    if(vlaues == null){
        values = initializeVlaue(currentThread);  //对空值进行初始化
    }
    values.put(this,value);  //存储
}

在set()方法中,首先会通过values方法来获取当前线程中ThreadLocal数据,接着会对使用put()方法对ThreadLocal的值进行存储,在localValues内部有一个数组:private Obkect[] table,ThreadLocal的值就存在这个table数组中。

  • get方法
public T get(){
    Thread currentThread = Thread.currentThread();
    Values values = values(currentThread);
    if(values != null){
        Object[] table = values.table;
        int index = hash & values.mask;
        if(this.reference == table[index]){
            return(T) table[index+1];
        }
    }
    return(T) values.getAfterMiss(this);
}

在get()方法中的逻辑就比较清晰,它主要是取出当前线程的localValues对象,如果这个对象为null,那么返回初始值;如果不为null,那就取出它的table数组并找出ThreadLocal的reference对象在table数组中的位置。

从set和get方法中可以看出,ThreadLocal所操作的对象都是当前线程的localValues对象的table数组,因此在不同线程中访问同一个ThreadLocal的set和get方法都仅仅是局限在它们各自线程的内部。

2.消息队列的工作原理

概念:消息队列在Android中指的是MessageQueue,MessageQueue主要包含两个操作:插入和读取,对应的方法分别是enqueueMessage和next。

  • enqueueMessage方法
boolean enqueueMessage(Message msg,long when){
    ...
    synchronized(this){
        ...
        msg.markUse();
        msg.when = when;
        Message p = mMessages;
        boolean needWake;
        if(p == null || when == 0 || when < p.when){
            msg.next = p;
            needWake = mBlocked;
        }
        else{
            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;
            prev.next = msg;
        }
        if(needWake){
            nativeWake(mPtr);
        }
    }
    return false;
}

在enqueueMessage()方法中主要就是进行的单链表的插入操作。

  • next方法
Message next(){
    ...
    int pendingIdleHandleCount = -1;
    int nextPollTimeoutMillis = 0;
    for( ; ;){
        if(nextPollTimeoutMillis != 0){
            Binder.flushPendingCommands();
        }
        nativePollOnce(ptr,nextPollTimeoutMillis);
        synchronized(this){
            final long now = SystemClock.uptimeMillis();
            Message prevMsg = null;
            Message msg = mMessages;
            if(msg != null && msg.target == null){
                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(false) Lod.v("");
                    return msg;
                }
            }
            else{
                nextPollTimeoutMillis = -1;
            }
        }
    }
}

next方法是一个无限循环的方法,如果消息队列中没有消息,那么next方法会一直阻塞在这里,如果有新消息到来时,next方法就会返回这条消息并将其从单链表中移除。

3.Looper的工作原理

概念:Looper在消息机制中的主要就是扮演者消息循环的角色,它会不停的从MessageQueue中查看是否有新消息,如果有新消息就会立刻处理,否则就会阻塞在那里。

Looper的创建:因为Handler的工作需要Looper,没有Looper的线程就会被报错,在一个线程中创建Looper的方法如下:

new Thread("Thread#2"){
    @Override
    public void run(){
        Looper.prepare();  //创建Looper
        Handler handler = new Handler();
        Looper.loop();  //开启Looper的消息循环
    };
}.start();

除了Looper的的perpare()的方法之外,系统还提供了prepareMainLooper()方法,该方法主要是给主线程,即ActivityThread创建Looper使用的,不过其本质也是通过prepare来实现的。

Looper的退出:Looper提供了quit和quitSafely来退出一个Looper,二者的区别是:quit会直接退出Looper,而quitSafely只是设定一个退出标记,只有把消息队列中所有的消息处理完毕之后才会安全的退出。Looper退出后,通过Handler发送的消息会失败。在子线程中,如果手动为其创建了Looper,那么在所有的事情完成之后应该调用quit方法来终止消息循环,否则这个子线程就会一直处于等待的状态。

4.Handler的工作原理

概念:Handler的工作主要包含消息的发送和接收过程。消息的发送可以通过post以及send的一系列方法来实现(post的一系列方法最终是通过send的以系列方法来实现的);而消息的接收和处理主要是。下面来分别介绍。

消息的发送:Handler消息的发送的典型过程如下:

public final boolean sendMessage(Message msg){
    return sendMessageDelayed(msg,0);
}


public final boolean sendMessageDelayed(Message msg,long delayMills){
    if(delayMills < 0){
        delayMills = 0;
    }
    return sendMessageAtTime(msg,SystemClock.uptimeMills() + delayMills);
}


public boolean sendMessageAtTime(Message msg,long uptimeMills){
    MessageQueue queue = mQueue;
    if(queue == null){
        RunTimeException e = new RunTimeException(this + "sendMessageAtTime() called with no mQueue");
        Log.w("");
        return false;
    }
    return enqueueMessage(queue,msg,uptimeMills);
}


private boolean enqueueMessage(MessageQueue queue,Message msg,long uptimeMills){
    msg.target = this;
    if(mAsynchronous){
        msg.setAsynchronous(true);
    }
    return queue.enqueueMessage(msg,uptimeMills);
}

Handler的发送消息过程结束之后,MessageQueue的next方法就会返回这条信息给Looper,Looper收到消息后就开始处理了,不过最终还是会交由给Handler的dispatchMessage()方法来进行,之后就进入了处理消息阶段。

消息的处理:Handler处理消息的过程如下:

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

首先会判断Message的callback是否为null,如果不为null,则会调用handleCallback()方法来处理消息,handleCallback方法的实现如下:

private static void handleCallback(Message message){
    message.callback.run();
}

接着还会检查mCallback是否为null,不为null就调用mCallback的handleMessage方法来处理消息,其中Callback是一个接口。最后调用Handler的handleMessage方法来处理消息。

三.主线程的消息循环

过程:Android的主线程就是ActivityThread,主线程的入口方法为main,在main方法中会进行Looper和MessageQueue的创建,以及Looper的开启的操作。

public static void main(String[] args){
    Looper.prepareMainLooper();
    ActivityThread thread = new ActivityThread();
    thread.attach(false);

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

    AsyncTask.init();

    if(false){
        Looper.myLooper().setMessageLogging(new LogPrinter(Log.DEBUG,"ActivityThread"));
    }
    Looper.loop();
}

主线程的消息循环开始了以后,ActivityThread还需要一个Handler来和消息队列进行交互,这个Handler就是ActivityThread.H,它内部定义了一组消息类型,主要包含了四大组件的启动和等待等过程。

主线程消息循环模型:主线程通过ApplicationThread和AMS进行进程间的通信,AMS以进程间通信的方式完成ActivityThread的请求后会回调ApplicationThread中的Binder方法,然后ApplicationThread会向H发送消息,H收到消息后会将ApplicationThread中的逻辑切换到主线程中执行。

你可能感兴趣的:(Android进阶(10)| Android的消息机制)