文档章节

Handler详解

libvirus
 libvirus
发布于 2016/05/22 18:40
字数 1043
阅读 14
收藏 0
点赞 2
评论 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里的管道实现的。希望以后搞明白了那一块的代码,在来更新。

© 著作权归作者所有

共有 人打赏支持
libvirus
粉丝 0
博文 2
码字总数 1315
作品 0
朝阳
程序员
读博文学Android

学习Android的过程中得到来自互联网上乐于分享和奉献的人们的帮助,这里收集了一些Android相关的知识点的介绍,研究,实践的博文地址。每篇文章将带给学习者更多的帮助,有些地址需要FQ的帮助...

secondriver ⋅ 2015/12/18 ⋅ 0

消息驱动 Looper类

Android异步处理系列文章索引 Android异步处理一:使用Thread+Handler实现非UI线程更新UI界面 Android异步处理二:使用AsyncTask异步更新UI界面 Android异步处理三:Handler+Looper+MessageQ...

charlessun ⋅ 2014/08/09 ⋅ 0

Go的http包详解

Go的http有两个核心功能:Conn、ServeMux. 1.Conn的goroutine 与我们一般编写的http服务器不同, Go为了实现高并发和高性能, 使用了goroutines来处理Conn的读写事件, 这样每个请求都能保持独立...

壬癸甲乙 ⋅ 2013/08/16 ⋅ 0

[Android] Handler详解

前言   Android的消息传递机制是另外一种形式的“事件处理”,这种机制主要是为了解决Android应用中多线程的问题,在Android中不 允许Activity新启动的线程访问该Activity里的UI组件,这样...

枫兮兮 ⋅ 2014/02/24 ⋅ 0

Handler和Looper详解

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

z.net ⋅ 2013/06/19 ⋅ 0

Android HandlerThread详解

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

VNanyesheshou ⋅ 2017/07/14 ⋅ 0

JFinal路由规则原理详解

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

山东小木 ⋅ 2016/02/15 ⋅ 0

详解Android中Handler的使用方法

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

我叫leo- ⋅ 2016/04/27 ⋅ 0

springmvc处理流程详解

一、首先了解springMVC的组件定义及用途 1.DisPatcherServlet:前端控制器(不需要程序员开发) 用户请求到达前端控制器,它相当于MVC模式中的C(Controller),DispatcherServlet是整个流程...

J星星点灯 ⋅ 2017/09/23 ⋅ 0

AsyncTask 的实现原理

在《Android异步处理二:使用AsyncTask异步更新UI界面》一文中,我们介绍了如何使用AsyncTask实现异步下载图片,并且更新图片到UI界面的方法。本篇我们将学习Framework层AsyncTask的实现原理...

鉴客 ⋅ 2011/09/17 ⋅ 1

没有更多内容

加载失败,请刷新页面

加载更多

下一页

Spring Bean基础

1、Bean之间引用 <!--如果Bean配置在同一个XML文件中,使用local引用--><ref bean="someBean"/><!--如果Bean配置在不同的XML文件中,使用ref引用--><ref local="someBean"/> 其实两种......

霍淇滨 ⋅ 7分钟前 ⋅ 0

05、基于Consul+Upsync+Nginx实现动态负载均衡

1、Consul环境搭建 下载consul_0.7.5_linux_amd64.zip到/usr/local/src目录 cd /usr/local/srcwget https://releases.hashicorp.com/consul/0.7.5/consul_0.7.5_linux_amd64.zip 解压consu......

北岩 ⋅ 10分钟前 ⋅ 0

Webpack 4 api 了解与使用

webpack 最近升级到了 v4.5+版 01 官方不再支持 node4 以下版本 官方不再支持 node4 以下版本官方不再支持 node4 以下的版本,所以如果你的node版本太低,先开始升级node吧!话说node10 ...

NDweb ⋅ 19分钟前 ⋅ 0

使用nodeJs安装Vue-cli

Vue脚手架就是一个Vue框架开发环境 脚手架的意思是帮你快速开始一个vue的项目,也就是给你一套vue的结构,包含基础的依赖库,只需要 npm install就可以安装,让我们不需要为了编辑或者一些其...

木筏笔歆 ⋅ 52分钟前 ⋅ 0

【微信小程序开发实战】0x00.开发前准备工作

写在开始 本人资深后端码农一枚,近期项目需求,接触到了微信小程序,将学习过程整理成文分享给小伙伴们,由于是边学边整理难免有表述不对的地方,望大家及时指正,感谢。 本人微信号: dream...

dreamans ⋅ 今天 ⋅ 0

linux redis的安装和php7下安装redis扩展

安装redis服务器 (1)下载安装包: $ wget http://download.redis.io/releases/redis-2.8.17.tar.gz (2)编译程序: $ tar xzf redis-2.8.17.tar.gz $ cd redis-2.8.17 $ make $ cd src &&......

concat ⋅ 今天 ⋅ 0

Guava EventBus源码解析

一、EventBus使用场景示例 Guava EventBus是事件发布/订阅框架,采用观察者模式,通过解耦发布者和订阅者简化事件(消息)的传递。这有点像简化版的MQ,除去了Broker,由EventBus托管了订阅&...

SaintTinyBoy ⋅ 今天 ⋅ 0

http怎么做自动跳转https

Apache 版本 如果需要整站跳转,则在网站的配置文件的<Directory>标签内,键入以下内容: RewriteEngine on RewriteCond %{SERVER_PORT} !^443$ RewriteRule ^(.*)?$ https://%{SERVER_NAME......

Helios51 ⋅ 今天 ⋅ 0

Python爬虫,抓取淘宝商品评论内容

作为一个资深吃货,网购各种零食是很频繁的,但是能否在浩瀚的商品库中找到合适的东西,就只能参考评论了!今天给大家分享用python做个抓取淘宝商品评论的小爬虫! 思路 我们就拿“德州扒鸡”...

python玩家 ⋅ 今天 ⋅ 0

MySQL 内核深度优化

MYSQL数据库适用场景广泛,相较于Oracle、DB2性价比更高,Web网站、日志系统、数据仓库等场景都有MYSQL用武之地,但是也存在对于事务性支持不太好(MySQL 5.5版本开始默认引擎才是InnoDB事务...

java高级架构牛人 ⋅ 今天 ⋅ 0

没有更多内容

加载失败,请刷新页面

加载更多

下一页

返回顶部
顶部