Handler使用小结
个人概念里面handler用来更新UI。一直有一个问题困恼我,为什么我在主线程里面创建一个Handler不需要传递传递Looper,而在一个子线程里面必须调用Looper.prepare, Looper.loop。今天看了看源码,终于知道里面的原委。个人觉得一切和ThreadLocal有关,关于ThreadLocal,请阅读如下博客:Android的消息机制之ThreadLocal的工作原理。 简而言之,ThreadLocal和当前线程绑定,如果handler在UI线程里面创建,ThreadLocal已经和主线程绑定,即使handler传入为空,也可以拿到主线程的looper,代码如下,
mLooper = Looper.myLooper();
if (mLooper == null) {
throw new RuntimeException(
"Can't create handler inside thread that has not called Looper.prepare()");
}
public static @Nullable Looper myLooper() {
return sThreadLocal.get();
}
我们知道,在app启动时候,在ActivityThread里面的main函数被执行:
Looper.prepareMainLooper(); ActivityThread thread = new ActivityThread();
thread.attach(false); if (sMainThreadHandler == null) {
sMainThreadHandler = thread.getHandler();
} if (false) {
Looper.myLooper().setMessageLogging(new
LogPrinter(Log.DEBUG, "ActivityThread"));
} // End of event ActivityThreadMain.
Trace.traceEnd(Trace.TRACE_TAG_ACTIVITY_MANAGER);
Looper.loop();
综合上面代码,looper已经在app启动的时候创建,所以 Looper.myLooper()取得的是UI主线程对应的looper,没有错误抛出。如果handler实在子线城里面创建:
new Thread(new Runnable() {
@Override
public void run() {
Handler handler = new Handler() {
@Override
public void handleMessage(Message msg) {
super.handleMessage(msg);
}
};
}
}).start();
可以很容易得出结论,子线程没有和ThreadLocal绑定,所以ThreadLocal里面的looper为空,如下异常抛出:
if (mLooper == null) {
throw new RuntimeException(
"Can't create handler inside thread that has not called Looper.prepare()");
}
既然有上面问题,如何在子线程里面创建handler呢?
new Thread(new Runnable() {
@Override
public void run() {
Looper.prepare();
Handler handler = new Handler(Looper.myLooper()) {
public void handleMessage(android.os.Message msg) {
// XXX
}
};
Looper.loop();
}
}).start();
继续看Looper.prepare:
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));
}
ThreadLocal的set方法如下, 可以看到内部ThreadLocalMap已当前线程为key进行绑定。
public void set(T value) {
Thread t = Thread.currentThread();
ThreadLocalMap map = getMap(t);
if (map != null)
map.set(this, value);
else
createMap(t, value);
}
这样当前线程和 sThreadLocal就绑定了,Looper.myLooper()得到的就是上面创建的 new Looper(quitAllowed)。
当然聪明的google意识到这个问题,所以有个HandlerThread可以省去手动调用prepare和loop的烦恼,核心代码如下:
public class HandlerThread extends Thread {
@Override
public void run() {
mTid = Process.myTid();
Looper.prepare();
synchronized (this) {
mLooper = Looper.myLooper();
notifyAll();
}
Process.setThreadPriority(mPriority);
onLooperPrepared();
Looper.loop();
mTid = -1;
}
}
Handler使用小结的更多相关文章
- Handler学习小结
在android消息机制中Handler扮演着举足轻重的作用,(AsnyTask其实也是对Handler+Thread做了一层封装),ui线程超过5s就会报出ANR,一般耗时操作操作需要放在子线程中处 ...
- Unity 3D Framework Designing(4)——设计可复用的SubView和SubViewModel(Part 2)
在我们设计和开发应用程序时,经常要用到控件.比如开发一个客户端WinForm应用程序时,微软就为我们提供了若干控件,这些控件为我们提供了可被定制的属性和事件.属性可以更改它的外观,比如背景色,标题等, ...
- Unity应用架构设计(4)——设计可复用的SubView和SubViewModel(Part 2)
在我们设计和开发应用程序时,经常要用到控件.比如开发一个客户端WinForm应用程序时,微软就为我们提供了若干控件,这些控件为我们提供了可被定制的属性和事件.属性可以更改它的外观,比如背景色,标题等, ...
- Netty学习笔记(三)——netty源码剖析
1.Netty启动源码剖析 启动类: public class NettyNioServer { public static void main(String[] args) throws Excep ...
- Handler,Thread,Looper之间关系小结
http://blog.csdn.net/sunxingzhesunjinbiao/article/details/6794840 (1) Looper类别用来为一个线程开启一个消息循环.默认情况下A ...
- Android Handler之使用小结
在android开发中,使用Handler处理各种消息机制. Handler用于处理和从队列MessageQueue中得到Message.一般我们要重写Handler的handleMessage(Me ...
- iOS--->微信支付小结
iOS--->微信支付小结 说起支付,除了支付宝支付之外,微信支付也是我们三方支付中最重要的方式之一,承接上面总结的支付宝,接下来把微信支付也总结了一下 ***那么首先还是由公司去创建并申请使用 ...
- Android消息传递之Handler消息机制
前言: 无论是现在所做的项目还是以前的项目中,都会遇见线程之间通信.组件之间通信,目前统一采用EventBus来做处理,在总结学习EventBus之前,觉得还是需要学习总结一下最初的实现方式,也算是不 ...
- CSS属性小结之--半透明处理
项目中经常有遇到需求半透明的情况,如图片.文字.容器.背景等等,每次都要去翻以前的项目,不甚其烦.现在一次性做个小结,方便自己查阅,也同时分享给大家: 一. 元素容器透明 .div{ opacity: ...
随机推荐
- python-Word模板填充-docxtpl
docxtpl 按指定的word模板填充内容 安装 pip install docxtpl 示例 from docxtpl import DocxTemplate data_dic = { 't1': ...
- three.js初探,立体几何入手(一)
前言:首先先推荐一篇博客,关于webgl原理,讲的非常之通俗易懂了 图解WebGL&Three.js工作原理 webGL可以理解为openGL ES2.0 (webGL2.0 - openG ...
- Day 4 变量常量
编辑语言的分类 编程语言,他是人与计算机沟通的一种介质 机器语言 计算机只认识0和1,为了和计算机沟通,你也得认识0和1 优点:执行效率快 缺点:普通人根本就写不了这种代码,开发效率低 汇编语言 他还 ...
- requests库爬取猫眼电影“最受期待榜”榜单 --网络爬虫
目标站点:https://maoyan.com/board/6 # coding:utf8 import requests, re, json from requests.exceptions imp ...
- Activiti之流程通过、驳回、会签、转办、中止、挂起等核心操作封装(Activiti5.9)
http://blog.csdn.net/rosten/article/details/38300267 package com.famousPro.process.service.impl; imp ...
- 缓存之Memcache
Memcache Memcached 是一个高性能的分布式内存对象缓存系统,用于动态Web应用以减轻数据库负载.它通过在内存中缓存数据和对象来减少读取数据库的次数,从而提高动态.数据库驱动网站的速度. ...
- 不安全代码只会在使用 /unsafe 编译的情况下出现
在你的项目属性页面里面,把是否包含unsafe代码的选项选上
- 再次精读《javascript高级程序设计第3版》学习笔记(1)
第一次拿起这本书是2016年暑假,时隔2年,又一次开始研读这本经典书籍.每次读,都是对之前的一次沉淀和总结,每次都会有新的收获.
- Cannot Connect to Database Server
好久没登数据库了,今天登陆时忽然要输入密码,然后一登结果就报了下图的错. 之前也发生过这种情况,但是重启服务就好了,这次重启后依然不行. 后来密码用root居然就登进去了,可是真不记得有改过密码 不知 ...
- 安装pyspider遇到的坑
pyspider是国人写的一款开源爬虫框架,个人觉得这个框架用起来很方便,至于如何方便可以继续看下去. 作者博客:http://blog.binux.me/ 安装pyspider安装pyspider: ...