Handler, Thread, Looper, Message,一图胜千言

这里写图片描述
问个问题:如果两个handler共享一个Looper,那么HandlerA发送的消息,HandlerB会不会收到嗫?
如果你不知道,那就看看我这篇文章,如果知道就别看了。。。

Handler大家一定太熟悉了,就是发送Message的,然后在handler关联的线程里处理Message。一般用来通知消息或者切换线程工作之类的。
一个Thread对应一个Looper,Looper就是一个循环体,Looper的作用就是给Thread用来循环处理消息的。当然如果你的Thread创建不需要sendMessage什么的,那当然就不需要创建一个Looper,比如你只是打印个字符串而已。。。
Looper既然是循环处理消息的话,那Looper中肯定有个Message的队列,没错,就是MessageQueue。MessageQueue就是记录Message队列的,采用链表的方式,并且记录列表头部指针(Java没有指针的概念,就是用个变量记录第一个Message。。。)。
看下Looper使用的例子:

class LooperThread extends Thread {
    public Handler mHandler;

    public void run() {
        Looper.prepare();

        mHandler = new Handler() {
            public void handleMessage(Message msg) {
                // process incoming messages here
            }
        };

        Looper.loop();
    }
}

这是个很简单的例子,在创建Thread的时候,先准备好Looper,只需要调用Looper.prepare()就可以了,看下prepare方法:

    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));
    }
    public void set(T value) {
        Thread currentThread = Thread.currentThread();
        Values values = values(currentThread);
        if (values == null) {
            values = initializeValues(currentThread);
        }
        values.put(this, value);
    }

大概就是得到当前的Thread,然后new一个Looper关联到Thread上。接下来就是生命一个Handler,看下Handler的构造函数:

    public Handler() {
        this(null, false);
    }

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

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

可以看到Handler会获取当前线程的Looper,通过Looper.myLooper得到,然后记录Looper和Looper的MessageQueue,当然你可以调用Handler其他的构造函数来指定Looper等。
然后调用Looper.loop。loop函数中有一个死循环,是不断的读取MessageQueue中的Message来处理,如果队列为空,则该死循环会阻塞,知道有新的Message到来才会唤起。
讲了这么多,该讲讲主人公Message了,Message主要有以下的参数:

public final class Message implements Parcelable { 
    //Message传递的一些参数
    public int what;
    public int arg1; 
    public int arg2;
    public Object obj;
    //记录发送方
    public Messenger replyTo;

    public int sendingUid = -1;

    //记录当前Message是不是正在被使用,因为Message可以重复利用,所以需要有变量记录
    /*package*/ static final int FLAG_IN_USE = 1 << 0;

    /** If set message is asynchronous */
    /*package*/ static final int FLAG_ASYNCHRONOUS = 1 << 1;

    /** Flags to clear in the copyFrom method */
    /*package*/ static final int FLAGS_TO_CLEAR_ON_COPY_FROM = FLAG_IN_USE;

    /*package*/ int flags;

    //在MessageQueue中排序时是通过该值来排序
    long when;

    /*package*/ Bundle data;

    //记录该Message是要发送给哪个Handler来处理
    Handler target;

    /*package*/ Runnable callback;

    //刚刚提到在MessageQueue中是以链表的方式记录,所以next相当于指针。
    /*package*/ Message next;
}

从参数中,可以将Message分为两类,一种是携带参数信息的(what, arg1, arg2等),一种是携带runnable的。后者用handler执行的时候,就是直接调用runnable.run方法。对应到handler的话就是两种发消息的方法:

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

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

如果调用post的话,会将runnable封装到Message中。
那如何创建一个Message呢?
可以通过调用Message.obtain(…)或者handler.obtainMessage(…)来调用,都是一样的,handler.obtainMessage最后也都是调用Message里面的方法。
在创建Message的时候,要指定Message的target是谁!!!当从MessageQueue中取出来会将该message发给message.target来处理。所以如果两个handler共享一个Loop,通过HandlerA发送的消息只能由HandlerA来处理,HandlerB不会收到。

下面问个问题:
如何在一个子线程中弹toast?
是这样么?

new Thread(new Runnable() {
            @Override
            public void run() {
                Toast.makeText(TestActivity.this,"lall",Toast.LENGTH_LONG).show();
            }
        }).start();

no,no,no。当你这么调的时候会发现出错了。这里要提醒下Toast中用到了handler。所以如果你直接像上面这么写会出错,因为在该子线程中Looper还没prepare好,所以创建handler的时候会出错。所以这就要引入一个新的Thread,就是handlerThread,该thread在创建的时候就会自己创建一个Looper并绑定,所以你可以这么做:

        HandlerThread t = new HandlerThread("thread");
        t.start();
        Handler handler = new Handler(t.getLooper());
        handler.post(new Runnable() {
            @Override
            public void run() {
                Toast.makeText(TestActivity.this,"ddd",Toast.LENGTH_LONG).show();
            }
        });
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值