Handler-Looper中的生产者消费者模型

如果你在网上搜索的时候不幸地搜到这篇文章,实在抱歉啊,我不太会写文章。

话说Handler-Looper,从听到这个东西到着手看它的源代码分析一下着实过了一年。Handler-Looper是干嘛用的?主要功能就是做线程交互吧,android对动画的实现用的也是它。

嗯,如果你听说生产者-消费者(《操作系统》)模型,这个Handler-Looper也许可以套用一下。调用Handler的线程就是生产者,生产要执行的任务;Looper绑定的线程就是消费者,负责消化(执行)任务。这些任务通过一个队列从生产者传给消费者。这就形成了N个生产者,1个消费者的模型。当队列中没有任务的时候,消费者就等着,直到有生产者向队列中添加了任务。然后就需要按照这个模型分析咯。

  • 生产者:其他线程,通过调用Handler中的post系列方法向队列中放任务。放任务的时候,如果Looper线程睡着了就顺便上一巴掌叫醒他去工作。
  • 消费者:Looper线程,执行Looper.prepare()的线程就是Looper线程啦。不停地调用MessageQueue.next()去拿任务,有可能阻塞。其实就一个死循环嘛。
  • 队列:MessageQueue,可以阻塞和唤醒Looper线程。在调用next()的时候,如果有任务则执行;没有则阻塞。
看源代码中的一段例子:
class LooperThread extends Thread {
    public Handler mHandler;

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

        mHandler = new Handler() {
            // 可以不覆盖这个方法
            public void handleMessage(Message msg) {
                // 根据msg中的内容执行某些操作
            }
        };

        Looper.loop();
    }
}
看几个地方:
  • mHandler是public方法,使用者用mHandler来向队列传数据
  • 队列在哪?队列在Looper中,可是怎么传给Handler?暗送秋波啊~哈哈!嗯,此时你得先知道一个叫LocalThread的东西,这个东西给每个线程提供一个存物箱。Looper.prepare()的时候,将自己存到当前线程的这个存物箱里了。Handler在new的时候,从所在线程的这个存物箱中将Looper拿出来了,然后当然也获得了里面的队列。所以,当你突发奇想在某个线程中新建了Handler时,如果这个线程有Looper的话,直接使用这个Looper;如果没有Looper的话,Handler自己去新建一个Looper是不可能的,直接崩掉 >_<|||
  • Looper.loop()就是执行会被阻塞的死循环。
  • handleMessage()其实可以不用覆盖,如果你调用handler的post传入Runnable的话。如果你调用sendMessage()传入Message,那就得覆盖这个方法了,否则就没有然后了。这两者怎么选?如果调用的是View的handler,乖乖传入runnable吧;如果你想写通用的消息循环工具,也传入runnable吧;如果你想写的东西只为了执行某些任务,就用这种写法,就是扩展的时候会比较头疼,因为里面要用到恶心的switch-case。
实际上,上面这个例子写完了,就是一个消息队列了。调用looperThread.start()之后稍等一下,就可以向这个队列传入任务了。简单吧╮(╯3╰)╭
google为了实现这个机制,写了四个类:Handler, Looper, MessageQueue和Message。看源代码之后会惊奇地发现,功能不多。
  • Handler:obtainMessage()系列,用于新建消息。新建Message不用new Message()噢,因为这里的Message是会被循环使用的。post()系列,用于向队列发送Runnable的。sendMessage()系列,用于向队列中传Message。remove()系列,用于从队列中删除Runnable或Message
  • Looper:prepare()初始化Looper。looper()执行死循环。其他那些都是浮云。
  • MessageQuere,还真不是咱能玩的。主要的功能,入队enqueueMessage()和出队next()都是package级方法,咱调用不了。
  • Message:Handler中的obtainMessage()就是调用这里的obtain()方法。每个Message都需要指定Handler,所以让Handler创建就好了。里面有用的是4个公共域:what, arg1, arg2, obj,用于存放给Handler.handleMessage()的参数的。前三个域是int类型,obj是Object类型。

我就说我不太会写文章嘛,现在要说最重要的东西(一般都放在开头说),这个Handler-Looper是干嘛用的?分析一下:生产者消费者模型是用于解决多线程间同步的,那Handler-Looper也就是干这个的。主要用于工作线程通知UI线程刷新界面。一般情况下我们用不到这个。在做工作线程时主要用AsyncTask,或者调用Activity.runOnUiThread()来执行UI操作。那么,好吧,很不建议你把工作线程封装到View中,这样工程结构将会很乱。调用View.getHandler()时会返回UI线程的Handler(或者是null),然后就可以在View中封装的工作线程里调用UI线程执行刷新了。

抛去UI的问题,如果你只是要做一个任劳任怨的工作线程来接收UI线程的各个命令的话,这么做也行吧~

差不多说完了,剩下的就意会吧( ̄︶ ̄)↗

发布了0 篇原创文章 · 获赞 8 · 访问量 14万+
展开阅读全文

没有更多推荐了,返回首页

©️2019 CSDN 皮肤主题: 大白 设计师: CSDN官方博客

分享到微信朋友圈

×

扫一扫,手机浏览