文档章节

Handler详解

libvirus
 libvirus
发布于 2016/05/22 18:40
字数 1043
阅读 15
收藏 0

Handler详解

##一,概述 因为Android里的控件都是线程不安全的,更新UI的代码必须在主线程所有Google给我们提供了一个线程通信的类。 而且Android的各种事件,Activity,Service组件的方法回调,也是基于Hander的。 这就是Handler。其实他们主要是由三个主要的类构成 Looper , Handler , MessageQueue。

##二,Looper 我相信写过从主线程发送消息通知子线程的人都应该刻这一段代码

        Looper.prepare();
        Handler handler=new Handler(){
            @Override
            public void handleMessage(Message msg) {
                super.handleMessage(msg);
            }
        };
        Looper.loop();

为什么在主线程写Handler不用Looper.prepare(); Looper.loop();呢,那是因为主线程已经为我们做了这些工作。 我们可以看看这两行代码做了什么事。如下,Looper.prepare()主要是初始化工作,创建一个Looper对象放入ThreadLocal当中。然后新建一个MessageQueue对象。 我们通过Handler 发送的消息就放在这个队列当中。

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

在看看Looper.loop()又做了点什么事情

    /**
     * Run the message queue in this thread. Be sure to call
     * {@link #quit()} to end the loop.
     */
    //代码有删改,完整的代码请看源码
    public static void loop() {
        final Looper me = myLooper();
        final MessageQueue queue = me.mQueue;

        for (;;) {
            Message msg = queue.next(); // might block
            msg.target.dispatchMessage(msg);
            msg.recycleUnchecked();
        }
    }

这个方法很简单只是把死循环队列当中的消息,有消息就msg.target.dispatchMessage去执行,dispatchMessage这个方法是不是很熟悉呢,其它msg.target 对象就是Handler对象,至于怎么放到Message当中去的,后边在讲。有细心的同学可能注意到这是一个死循环,而且队列有可能会阻塞,前面有讲到主线和里替我们 初始化了Looper。那么主线程为又是怎么执行代码的呢。当然原因很简单方法回调和事件都是通过主线程里的Handler发送到队列里,然后执行的。比如你手机卡的 时候你点返回,没有反应,你连点几次的话,又退出程序了,因为事件都在队列里,执行完一个在执行别一个。 ##三,Handler 上面说到Looper.loop()从队列里取出来的Message给了msg.target,我说他是一个Handler对象,我们看看他是怎么放入消息中的。

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

所有发送消息的方法最后都是调用的这个方法。我们看到msg.target=this所有消息在放入消息队列之前都会持有发送消息的Handler对象。这就是哪个Handler发送的消息, 哪个Handler负责处理。 那么,Handler是怎么和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;
        mCallback = callback;
        mAsynchronous = async;
    }

我们看到从这个Looper.myLooper()方法里得到的Looper对象。

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

现在知道Looper对象是怎么来的了吧。如果在非主线程里new Handler那就必须要在这个线程里初始化一个Looper对象,用ThreadLocal保存起来。new Handler的时候 要查检在本线程里有没有这个对象,如果没有会报错。

##三,总结 对于Rxjava,RxAndroid 这类不用写Handler的类库,内部应该也是需要通过Handler post代码的。所以这种线程间通信的方法一定要明白。 当然这还些知道还很浅显。最核心的是消息队列的实现,消息队列是由Linux里的管道实现的。希望以后搞明白了那一块的代码,在来更新。

© 著作权归作者所有

共有 人打赏支持
上一篇: Http 请求
下一篇: Http 请求
libvirus
粉丝 0
博文 2
码字总数 1315
作品 0
朝阳
程序员
私信 提问
Handler+Looper+MessageQueue深入详解

在《Android异步处理一:使用Thread+Handler实现非UI线程更新UI界面》中,我们讲到使用Thread+Handler的方式来实现界面的更新,其实是在非UI线程发送消息到UI线程,通知UI线程进行界面更新,...

鉴客
2011/09/17
18.5K
9
Handler和Looper详解

关于这个话题,其实很早之前就想撰写相关来的稳当来加加深映像,或者当做技术笔记,但是一直都不知道从哪里开始比较合适.先看看网上给出的相关的定. Hanlder作用: 1)执行计划任务,你可以再预定...

z.net
2013/06/19
0
0
Android HandlerThread详解

转载请注明出处:http://blog.csdn.net/vnanyesheshou/article/details/75073307 对于Handler不太懂的可以参考我的这两篇文章: Android Handler的基本使用 深入理解Handler、Looper、Messa...

VNanyesheshou
2017/07/14
0
0
详解Android中Handler的使用方法

在Android开发中,我们经常会遇到这样一种情况:在UI界面上进行某项操作后要执行一段很耗时的代码,比如我们在界面上点击了一个”下载“按钮,那么我们需要执行网络请求,这是一个耗时操作,...

我叫leo-
2016/04/27
88
0
JFinal路由规则原理详解

《JFinal路由规则原理详解》 JFinal的路由规则比较灵活,提供了多种规则方式匹配,可以满足大多数应用场景。如果不满足您的需求,也可以轻松使用handler去扩展自己的路由规则。 访问localho...

山东小木
2016/02/15
827
0

没有更多内容

加载失败,请刷新页面

加载更多

oh-my-zsh 自定义

GitHub 地址 基于 oh-my-zsh 的自定义配置,增加了一些个人常用插件与皮肤。 采用的是 git submodule 来维护,包括 oh-my-zsh,之所以这么搞,主要是手头有多台 linux 需要维护, 每台机器、...

郁也风
今天
4
0
Docker安装踩坑:E_FAIL 0x80004005的解决

参考 菜鸟教程--Windows Docker 安装 http://www.runoob.com/docker/windows-docker-install.html 官方文档-Install Docker Toolbox on Windows https://docs.docker.com/toolbox/toolbox_in......

karma123
今天
5
0
js垃圾回收机制和引起内存泄漏的操作

JS的垃圾回收机制了解吗? Js具有自动垃圾回收机制。垃圾收集器会按照固定的时间间隔周期性的执行。 JS中最常见的垃圾回收方式是标记清除。 工作原理:是当变量进入环境时,将这个变量标记为“...

Jack088
昨天
17
0
大数据教程(10.1)倒排索引建立

前面博主介绍了sql中join功能的大数据实现,本节将继续为小伙伴们分享倒排索引的建立。 一、需求 在很多项目中,我们需要对我们的文档建立索引(如:论坛帖子);我们需要记录某个词在各个文...

em_aaron
昨天
27
0
"errcode": 41001, "errmsg": "access_token missing hint: [w.ILza05728877!]"

Postman获取微信小程序码的时候报错, errcode: 41001, errmsg: access_token missing hint 查看小程序开发api指南,原来access_token是直接当作parameter的(写在url之后),scene参数一定要...

两广总督bogang
昨天
33
0

没有更多内容

加载失败,请刷新页面

加载更多

返回顶部
顶部