个人概念里面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. python之做一个简易的翻译器(一)

    平时经常在网上翻译一些单词,突发奇想,可不可以直接调某些免费翻译网站的接口呢?然后做一个图形界面的翻译小工具?下面开始实践 1.先找一下有哪些免费翻译的接口 百度了一下关键字“免费翻译接口”,然后找到 ...

  2. python高阶函数(Map、Reduce、Filter、lamba)

    Map函数 map()函数接收两个参数,一个是函数,一个是序列,map将传入的函数依次作用到序列的每个元素,并把结果作为新的list返回. 代码如下: >>> def f(x): . ...

  3. 使用cookie保存用户名和密码

    效果图如下 从数据库中随意使用一个账号登录 登陆成功来到人中心 返回登录界面 实现代码如下 package com.test.controller; import java.io.IOExceptio ...

  4. 在java程序代码中打开文件

    class     TEST {      public  static  void  main(String[]  args){        System.out.println("He ...

  5. java protected修饰符说明

    1. 简介 对protected修饰符进行阐述,结合Object类的clone方法进行说明.其中clone方法如下:protected Object Object.clone(): 关于protect ...

  6. 如何正确可视化RAW(ARW,DNG,raw等格式)图像?

    为了正确可视化RAW图像,需要做好:白平衡.提亮以及色彩映射. import numpy as np import struct from PIL import Image import rawpy ...

  7. (JavaScript)实现上传图片实时预览和(文件)大小判断

    唉,为什么我一个做大数据和后端的要为前端耗尽心力啊??!! 昨天在做一个网页时遇到了一个问题,有一处需要插入图片,我原本的想法是获取到上传文件的URL,然后动态插入img标签,设置src为图片的URL ...

  8. 总结const、readonly、static三者的区别

    const:静态常量,也称编译时常量(compile-time constants),属于类型级,通过类名直接访问,被所有对象共享! a.叫编译时常量的原因是它编译时会将其替换为所对应的值: b.静态 ...

  9. BAT面试官告诉你如何回答你的职业规划

    前言(Why) 在面试中不论是在一面二面三面这种技术面,还是在最后的hr面,经常会被人问及,"谈谈你的职业规划"这种问题,我们回答的很可能会给我们的面试表现加分,如果回答地不好,对 ...

  10. idea新建maven工程没有artifacts

    原理,是因为没把新创建好的maven项目给设置成一个可被tomcat部署的web项目 选择个项目路径 配置artifacts,引入到tomcat就可以