个人概念里面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使用小结的更多相关文章

  1. Handler学习小结

    在android消息机制中Handler扮演着举足轻重的作用,(AsnyTask其实也是对Handler+Thread做了一层封装),ui线程超过5s就会报出ANR,一般耗时操作操作需要放在子线程中处 ...

  2. Unity 3D Framework Designing(4)——设计可复用的SubView和SubViewModel(Part 2)

    在我们设计和开发应用程序时,经常要用到控件.比如开发一个客户端WinForm应用程序时,微软就为我们提供了若干控件,这些控件为我们提供了可被定制的属性和事件.属性可以更改它的外观,比如背景色,标题等, ...

  3. Unity应用架构设计(4)——设计可复用的SubView和SubViewModel(Part 2)

    在我们设计和开发应用程序时,经常要用到控件.比如开发一个客户端WinForm应用程序时,微软就为我们提供了若干控件,这些控件为我们提供了可被定制的属性和事件.属性可以更改它的外观,比如背景色,标题等, ...

  4. Netty学习笔记(三)——netty源码剖析

    1.Netty启动源码剖析 启动类: public class NettyNioServer { public static void main(String[] args) throws Excep ...

  5. Handler,Thread,Looper之间关系小结

    http://blog.csdn.net/sunxingzhesunjinbiao/article/details/6794840 (1) Looper类别用来为一个线程开启一个消息循环.默认情况下A ...

  6. Android Handler之使用小结

    在android开发中,使用Handler处理各种消息机制. Handler用于处理和从队列MessageQueue中得到Message.一般我们要重写Handler的handleMessage(Me ...

  7. iOS--->微信支付小结

    iOS--->微信支付小结 说起支付,除了支付宝支付之外,微信支付也是我们三方支付中最重要的方式之一,承接上面总结的支付宝,接下来把微信支付也总结了一下 ***那么首先还是由公司去创建并申请使用 ...

  8. Android消息传递之Handler消息机制

    前言: 无论是现在所做的项目还是以前的项目中,都会遇见线程之间通信.组件之间通信,目前统一采用EventBus来做处理,在总结学习EventBus之前,觉得还是需要学习总结一下最初的实现方式,也算是不 ...

  9. CSS属性小结之--半透明处理

    项目中经常有遇到需求半透明的情况,如图片.文字.容器.背景等等,每次都要去翻以前的项目,不甚其烦.现在一次性做个小结,方便自己查阅,也同时分享给大家: 一. 元素容器透明 .div{ opacity: ...

随机推荐

  1. fabric私密数据学习笔记

    fabric私密数据学习笔记 私密数据分为两部分 一个是真正的key,value,它被存在 peer的私密数据库(private state)中. 另一部分为公共数据,它是真实的私密数据key,val ...

  2. JS 自由变量---JS 学习笔记(三) 补充

    自由变量:在 A 中作用域要用到的变量  x,并没有在 A 中声明,要到别的作用域中找到他,这个变量 x 就是自由变量.代码示例如下: var x = 20; function A (b) { ret ...

  3. pgsql 服务遇见的问题记录

    1.安装服务 命令 pg_ctl.exe register -N "pgsql" -D ../data 2.安装后启动失败的解决方式 2.1删除data文件夹下的postmaste ...

  4. 关于RedHat Linux无法使用yum命令安装gcc-c++问题

    初入职场,在给RedHat Linux安装环境的时候遇到这么个问题. 参考:http://www.linuxidc.com/Linux/2017-08/146548.htm [root@localho ...

  5. Linux之redis-cluster(集群配置)

    redis-cluster配置   为什么要用redis-cluster 1.并发问题 redis官方声称可以达到 10万/每秒,每秒执行10万条命令假如业务需要每秒100万的命令执行呢? 2.数据量 ...

  6. UML图概述

    UML图概述 UML是一种分析设计语言,即一种建模语言.UML是由图形符号表达的建模语言,其结构主要包括视图.图.模型元素和通用机制四部分. UML包括5种视图,分别是用户视图.结构视图.行为视图.实 ...

  7. js点击加载更多可以增加几条数据的显示

      <div class="list"> <div class="one"> <div class="img" ...

  8. IDEA外部工具配置-OpenJML篇

    帮助文档 jetbrains帮助文档:https://www.jetbrains.com/help/idea/settings-tools-external-tools.html 使用external ...

  9. numpy 数组索引数组

    在numpy中,数组除了可以被整数索引,还可以被数组索引. a[b]就是已数组b的元素为索引,读取数组a的值. 当被索引数组a是一维数组,b是一维或则多维数组时,结果维度维度与索引数组b相同. a = ...

  10. text——文本属性大全

    一.文字颜色(color:red;) <style> body {color:red} h1 {color:greenyellow} p.color {color:blue} </s ...