android 消息机制

android的消息机制,这肯定是被大家源码解析,分析坏了的一部分。首先这个消息机制用的比较频繁,主要用在子线程更新UI,再一个就是这个源码比较少,也是很好理解的,我感觉每个人都会来一篇消息机制的文章。

Android消息机制概述

说到Android的消息机制,大家肯定会想到Handler。是的,Android的消息机制主要是指Handler的运行机制以及Handler所附带的MessageQueue和Looper的工作过程。当我们工作的时候我们只要接触到Handler就可以了。

为什么要有Android消息机制?

我们知道Handler的主要作用是将一个任务切换到某个指定的线程去执行,比如Android规定访问UI只能在主线程中进行,如果在子线程中访问那么程序会抛异常,如下所示:

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

为什么系统不允许在子线程中访问UI呢?这是因为Android的UI控件不是线程安全的,如果在多线程中访问UI控件则会导致不可预期的状态。那为什么不对UI控件访问加锁呢?缺点有两个:首先加锁会让UI控件的访问的逻辑变的复杂;其次,锁机制会降低UI的访问效率。那我们不用线程来操作不就行了吗?但这是不可能的,因为Android的主线程不能执行耗时操作,否则会出现ANR。所以,从各方面来说,Android消息机制是为了解决在子线程中无法访问UI的矛盾。

在这里就不进行MessageQueue和Looper的分析了,大家如果想看可以百度,或者自己去看下源码就都可以看懂的。我们接下来主要分析Handler处理消息的几种方式,以及他们在执行时的顺序。

我们都知道主线程是可以直接new Handler()的,而在子线程中却是不可以的,我们去看下这是为什么?

if (mLooper == null) {
    throw new RuntimeException(
        "Can't create handler inside thread that has not called Looper.prepare()");
}

如果在子线程中会报这么一个错误,这是因为在子线程中没有Looper对象。如果子线程也想创建Handler,可以去参考HandlerThread这个类的实现。为什么主线程是可以的,那就要去找一个ActivityThread的类了,这是在应用启动的时候开启的一个线程也是传说中的UI线程或主线程,源码:

public static void main(String[] args) {
    ...
    //这个地方就是创建一个Looper,并且放在ThreadLocal里。下面会有源码
    Looper.prepareMainLooper();

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

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

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

    // End of event ActivityThreadMain.
    Trace.traceEnd(Trace.TRACE_TAG_ACTIVITY_MANAGER);
    // Loop.loop()是一个死循环,但是在没有消息的时候会堵塞
    Looper.loop();

    throw new RuntimeException("Main thread loop unexpectedly exited");
}
public static void prepareMainLooper() {
// 这里就是创建Looper的方法
    prepare(false);
    synchronized (Looper.class) {
        if (sMainLooper != null) {
            throw new IllegalStateException("The main Looper has already been prepared.");
        }
        // 这个地方就是把在prepare(false)中存入的Looper取出来
        sMainLooper = myLooper();
    }
}
private static void prepare(boolean quitAllowed) {
    if (sThreadLocal.get() != null) {
        throw new RuntimeException("Only one Looper may be created per thread");
    }
    //创建一个Looper放到ThreadLocal里面
    sThreadLocal.set(new Looper(quitAllowed));
}

public static @Nullable Looper myLooper() {
    return sThreadLocal.get();
}
这个地方用到了ThreadLocal,大家可以自己去自行百度。

好了这个地方已经解释了UI线程里面可以new Handler的原因。下面就是我们要解释Handler出来消息的几种方式。

在这我就默认大家都是知道Message在处理的时候是调用msg.target.dispatchMessage()方法来处理,这个msg.target就是我们Handler。下面我们来看下这个dispatchMessage方法

/**
 * Handle system messages here.
 */
public void dispatchMessage(Message msg) {
    if (msg.callback != null) {
        // 处理消息的第一种方式
        handleCallback(msg);
    } else {
        if (mCallback != null) {
            // 处理消息的第二种方式
            if (mCallback.handleMessage(msg)) {
                return;
            }
        }
        // 处理消息的第三种方式
        handleMessage(msg);
    }
}

在这里可以看出处理消息有三种方式,并且彼此不会重叠,都是执行一次。

第一种方式:

private static void handleCallback(Message message) {
    message.callback.run();
}
这个地方message.callback是什么地方给的呢?
handler.post(new Runnable() {
    @Override
    public void run() {

    }
});

public final boolean post(Runnable r)
{
   return  sendMessageDelayed(getPostMessage(r), 0);
}

private static Message getPostMessage(Runnable r) {
     //这个地方就是把Runnable赋值给Message的callback了,也就有我们上面代码的调用了
    Message m = Message.obtain();
    m.callback = r;
    return m;
}
第二种方式:Handler为了防止在创建是都要写一个子类,所以提供了一个接口,也就是Handler.Callback
public interface Callback {
    public boolean handleMessage(Message msg);
}
Handler的创建方式:
Handler handler = new Handler(new Handler.Callback() {
    @Override
    public boolean handleMessage(Message msg) {
        return false;
    }
});

这种方式处理完Message不要忘记返回true。

第三种方式:调用handleMessage方法

Handler的创建方式:

Handler handler2 = new Handler(){
    @Override
    public void handleMessage(Message msg) {
    }
};
就会调用我们写的handleMessage方法,进行处理Message。




评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值