利用Handler来“运装家具”

Handler是什么?Handler其实就是个工具类,来进行信息的发送和处理(应用)。

Handler传递信息的过程和把家具运从厂家运到供销商相似(这个过程有一点不一样)。

线程A是厂家,线程B是供销商,MessageQueue就是仓库,Handler是供销商的负责人,Message可以看做是家具,Looper可以看做仓库管理员(只负责一个厂家)。

Looper负责建仓库(prepare)、往仓库里存家具([Looper] enqueueMessage)、从仓库里取家具(loop)。
Handler负责把家具送到仓库相当于发货([Handler] enqueueMessage)、组装家具(dispatchMessage)。

现在我们把这个过程来捋一下,在供销商这边Looper要建仓库,建好仓库之后找个负责人到厂家运家具(实例化Handler),然后负责人去厂家运家具(handler.sendMessage(Message)),运到仓库时负责人想,供销商那边也是我负责,我怎么到那边去。想了一想,不如我钻到家具里,家具到了我也就到了。然后家具就带着负责人存入仓库,供销商这边的Looper就开始取家具,取出来之后负责人也从家具里钻出来了,开始组装家具(dispatchMessage)然后这个过程就结束了。

注意:当供销商是UI线程时,这时候的仓库已被系统给建好了,并且这个仓库一直存在,不会退出。所以不用再建仓库,也不用loop()。

代码:

public class MainActivity extends AppCompatActivity {
    private TextView textView;

    Handler handler;

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

        textView = (TextView) findViewById(R.id.text);

        textView.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                new MyThread().start();
                new Thread2().start();
            }
        });
    }

    //供销商
    class MyThread extends Thread {
        @Override
        public void run() {
            super.run();
            //建立仓库
            Looper.prepare();

            handler = new Handler() {

                //负责人组装家具
                @Override
                public void handleMessage(Message msg) {
                    super.handleMessage(msg);
                    Log.i("aaa", "MyThread");
                }
            };

            //从仓库取家具
            Looper.loop();

        }
    }

    //厂家
    class Thread2 extends Thread {
        @Override
        public void run() {
            super.run();
            //家具
            Message message = Message.obtain();
            message.what = 0;

            //负责人向仓库运家具
            handler.sendMessage(message);
        }
    }
}

传输过程在源码中,应用上看不出,所以我们看一下源码。我们按顺序开始。

建仓库:

public final class Looper {
    ````
    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));
    }

    private Looper(boolean quitAllowed) {
        mQueue = new MessageQueue(quitAllowed);
        mThread = Thread.currentThread();
    }
    ````
}

可以看到prepare()里调用的是prepare(boolean quitAllowed)方法,而prepare(boolean quitAllowed)中调用了Looper的构造方法(注意该构造方法是私有的),方法里实例化了一个MessageQueue,并取得了当前的线程。prepare(boolean quitAllowed)中把实例化的Looper存到ThreadLocal中。

当在ThreadLocal中取Looper时,只能取当前线程的Looper,用myLooper()方法获取当前线程的Looper。

这里就建好仓库了,然后找负责人:

public class Handler {
    final Callback mCallback;

    public interface Callback {
        public boolean handleMessage(Message msg);
    }
    ````
    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;
    }
    ````
}

在这个代码里可以看到当前线程必须实例化Looper不然就会返回错误。下面的mQueue就是MessageQueue,mCallback和Handler的实例化方式有关。

负责人发货handler.sendMessage(message):

public class Handler {

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

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

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

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

顺着sendMessage捋,最后找到enqueueMessage方法。其中的msg.target = this就是把当前的Handler绑在Message上,即负责人钻进家具里。queue.enqueueMessage(msg, uptimeMillis)就是Looper的插入,即将家具存入仓库。

仓库负责人取家具Looper.loop():

    public static void 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;

        // Make sure the identity of this thread is that of the local process,
        // and keep track of what that identity token actually is.
        Binder.clearCallingIdentity();
        final long ident = Binder.clearCallingIdentity();

        for (;;) {
            Message msg = queue.next(); // might block
            if (msg == null) {
                // No message indicates that the message queue is quitting.
                return;
            }

            // This must be in a local variable, in case a UI event sets the logger
            final Printer logging = me.mLogging;
            if (logging != null) {
                logging.println(">>>>> Dispatching to " + msg.target + " " +
                        msg.callback + ": " + msg.what);
            }

            final long traceTag = me.mTraceTag;
            if (traceTag != 0 && Trace.isTagEnabled(traceTag)) {
                Trace.traceBegin(traceTag, msg.target.getTraceName(msg));
            }
            try {
                msg.target.dispatchMessage(msg);
            } finally {
                if (traceTag != 0) {
                    Trace.traceEnd(traceTag);
                }
            }

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

  第2~6行:获取当前线程中的Looper,并从Looper中获得消息队列。
  第10~11行:确保当前线程属于当前进程,并且记录真实的token。clearCallingIdentity的实现是在native层,对于具体是如何实现的就不在进行分析。
  第14~18行:从消息队列中取出消息,并且只有当取出的消息为空的时候才会跳出循环。
  第27行:将消息重新交由Handler处理。
  第35~42行:确保调用过程中线程没有被销毁。
  第44行:对消息进行回收处理。
  和我们刚才猜想的一样,在loop中确实存在一个死循环,而唯一退出该循环的方式就是消息队列返回的消息为空。然后我们通过消息队列的next()方法获得消息。msg.target是发送消息的Handler,通过Handler中的dispatchMessage方法又将消息交由Handler处理。消息处理完成之后便对消息进行回收处理。

其中第27行将消息重新交由Handler处理。

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

该方法中有三个handleMessage(msg),分别对应Handler的三个实例化方式。这里第三个就是我们重写的handleMessage。到这里家具就运装完了。

参考资料:

Android的消息机制——Handler的工作过程

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值