Android系统Handler消息处理机制(一)

前言:

我接触Handler第一次的时候就比较懵逼,Handler handler=new Handler()然后调用handler.sendEmptyMessage();就可以发送消息了,然后在Handler的回调中处理消息.当时只是单纯觉得是一个消息队列,从这边发送消息,那边是一个死循环接收消息,然后调用回调函数打印.仔细没多想,现在具体想了一下,看了源码,才知道并不是那么简单.


那么具体那些问题需要思考呢?

1.队列到哪里?谁又在取消息分发?
2.死循环到底怎么一个循环法.
3.还有很多人误解的为什么主线程不会因为Looper.loop()里的死循环卡死?

带着这些问题,我们今天就具体看看源码怎么说

Looper

我们知道Looper类是一个线程的消息循环处理器
1.Looper构造方法私有.
2.Looper对象每个线程只能有一个.
3.并且通过静态prepare方法创建.
4.保存在ThreadLocal<Looper> sThreadLocal中(是一个线程有关的键值对存取容器)

  private Looper(boolean quitAllowed) {
        mQueue = new MessageQueue(quitAllowed);
        mThread = Thread.currentThread();
    }
    public static void prepare() {
        prepare(true);
    }

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

我们下来看看Looper类的loop方法

    public static void loop() {
        final Looper me = myLooper();//得到当前线程的looper
        if (me == null) {
            throw new RuntimeException("No Looper; Looper.prepare() wasn't called on this thread.");
        }
        final MessageQueue queue = me.mQueue;//从looper中拿出消息队列
        Binder.clearCallingIdentity();
        final long ident = Binder.clearCallingIdentity();
        for (;;) {
            Message msg = queue.next(); //进行遍历消息队列
            if (msg == null) {
                return;
            }
            Printer logging = me.mLogging;
            msg.target.dispatchMessage(msg);//拿到Handler进行分发事件
            final long newIdent = Binder.clearCallingIdentity();
            msg.recycleUnchecked();
        }
    }

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

loop()中就做了4个事情
1.得到当前线程的looper
2.从looper中拿出消息队列
3.进行遍历消息队列
4.拿到Handler进行分发事件

这里思考一个问题:既然知道ThreadLocal<Looper> sThreadLocal是一个拿取当前线程的Looper类,那么当前线程是在哪?
这里看下Handler的构造:

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

可以看出来我们一般使用在Activity中创建Handler然后发送消息,所以Handler中得到的也是Activity的线程.

问题来了:Activity的线程大家都说是UI线程,但是也没有人具体说怎么UI了,在哪里UI了,下面我就带大家溜溜源码.

图片出自Android系统大牛Gityuan:Activity启动流程篇:
http://gityuan.com/2016/03/12/start-activity/
这里写图片描述

具体我们看一看目标进程中的哪里创建了Activity对象

//ApplicationThread.java
public final void scheduleLaunchActivity(...) {
...
     sendMessage(H.LAUNCH_ACTIVITY, r);
 }
public void handleMessage(Message msg) {
    switch (msg.what) {
        case LAUNCH_ACTIVITY: {
            ...
            handleLaunchActivity(r, null);
        } break;
        ...
    }
}

private void handleLaunchActivity(ActivityClientRecord r, Intent customIntent) {
    ...
    Activity a = performLaunchActivity(r, customIntent);
    ...
}
private Activity performLaunchActivity(ActivityClientRecord r, Intent customIntent) {
    ...
    Activity activity = null;
    java.lang.ClassLoader cl = r.packageInfo.getClassLoader();
    //通过反射创建Activity
    activity = mInstrumentation.newActivity(cl, component.getClassName(), r.intent);
    //下面就是调用各种Activity的生命周期回调方法
    activity.attach(...);
    mInstrumentation.callActivityOnCreate(activity, r.state);
    activity.performStart();
    mInstrumentation.callActivityOnRestoreInstanceState(activity, r.state,r.persistentState);
    mInstrumentation.callActivityOnPostCreate(activity, r.state,r.persistentState);
    mInstrumentation.callActivityOnPostCreate(activity, r.state);
    return activity;
}

上面过程我们看出来是ApplicationThread类sendMessage(H.LAUNCH_ACTIVITY,r);在handleMessage的分发事件中创建出来了Activity对象,所以这个问题归结于这个分发事件在那个进程的那个线程中跑.

来看,首先发给消息的Handler是在ActivityThread类中创建的H对象

private class H extends Handler {
  public static final int LAUNCH_ACTIVITY  = 100;

也就是说,在Activity中的Looper对象是在ActivityThread所在的线程中.
那我们就来看看ActivityThread在那个线程中,我们看看ActivityThread创建的main方法

public static void main(String[] args) {
      ...
        Looper.prepareMainLooper();//创建属于此线程的Looper
        ActivityThread thread = new ActivityThread();
        thread.attach(false);
        ...
        Looper.loop();
    }
   public static void prepareMainLooper() {
        prepare(false);
        ...
    }
    private static void prepare(boolean quitAllowed) {
        ...
        sThreadLocal.set(new Looper(quitAllowed));
    }

到了这里我们惊喜的发现在ActivityThread的main()方法中创建了主线程的Looper,并且Activity和ActivityThread在同一个线程,即主线程

总结:

1.Looper类是Android中线程消息通信的重要类,扮演线程消息的处理器的角色
2.每个线程只能创建一个Looper对象
3.通过Looper.prepare()方法创建Looper对象,Looper.prepareMainLooper();创建主线程Looper对象
4.有了Looper对象用loop方法进入消息循环
5.loop方法不断从MessageQueue队列中拿出消息,然后分发给Handler的回调方法
6.一个Looper可以对应多个Handler对象
7.Looper方法在存取每个线程所属于的私有变量是通过ThreadLocal成员
8.在Activity中创建的Handler对象,中创建的Looper是和ActivityThread在一个线程中即主线程

下一节我们分析Handler,Message等其他有关重要的类

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值