从子线程不能直接新建一个Handler对象来剖析android的Handler机制
来源:互联网 发布:爬虫软件干嘛用 编辑:程序博客网 时间:2024/05/18 01:57
从子线程不能直接新建一个Handler对象来剖析android的Handler机制
前言
错误案例:在子线程中新建Handler报错:
java.lang.RuntimeException: Can't create handler inside thread that has not called Looper.prepare()
代码案例:
@Overrideprotected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); new Thread(){ @Override public void run() { new Handler(){ @Override public void handleMessage(Message msg) { super.handleMessage(msg); } }; } }.start();}
一、异常提示定位
首先我们到Handler类中去寻找错误提示的语句,在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()"); }
发现之所以不能再子线程中新建Handler对象的原因是用为Looper对象为null
再点开Looper.myLooper();的源代码:
发现
public static Looper myLooper() { return sThreadLocal.get();}
Looper对象是存放在
static final ThreadLocal<Looper> sThreadLocal = new ThreadLocal<Looper>();
中这个对象是以线程的ID为键值,所以get方法取出的都是当前线程对应的Looper对象
所以之所以不能再子线程中定义Handler对象的原因就是用为我们没有主动的新建一个Looper对象并放到sThreadLocal 中
进一步思考
如何在子线程中新建一个Looper对象?我们去查看Looper的public static void 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));}
发现调用这个方法即可新建一个Looper对象并放入该线程的sThreadLocal中
而sThreadLocal,是一个静态变量。在Looper.class被加载进内存的时候就已经初始化了,所以要想在子线程中新建一个Handler对象,可以用一下写法。
class LooperThread extends Thread { public Handler mHandler; public void run() { Looper.prepare(); mHandler = new Handler() { public void handleMessage(Message msg) { // process incoming messages here } }; Looper.loop(); }
当我们调用Looper.looper()方法开始,Looper就会不断了去轮询MessageQueue.这是一个先入先出的栈结构。
public static void loop() { …… for (;;) { //此处如果queue没有更新的msg了就会阻塞线程 Message msg = queue.next(); // might block if (msg == null) { // No message indicates that the message queue is quitting. return; } …… //执行msg msg.target.dispatchMessage(msg); …… //msg重置 msg.recycleUnchecked(); } }
注释表明当消息池为空的时候,轮询器会阻塞在那里,不会有额外的性能支出。在此还提出几个问题待以后再来讨论。
问题一:轮询器被阻塞后又是谁来负责唤醒呢?
问题二:轮询器所在的线程是哪个线程,这个线程有什么特点,主要用来干什么?
问题三:为什么在主线程就可以直接新建Handler,主线程的Looper又是在什么地方初始化的呢?
0 0
- 从子线程不能直接新建一个Handler对象来剖析android的Handler机制
- Android的线程消息机制(Handler机制剖析)
- Android Handler机制详解:在线程中新建Handler
- Android Handler机制剖析
- Android Handler机制剖析
- Android----Handler机制剖析
- 剖析Android-Handler机制流程
- Android线程之间的通讯机制Handler
- 子线程新建Handler为什么会报错?——浅谈Handler,Looper,Message之间的关系
- Android的消息机制,用Android线程间通信的Message机制,Android中Handler的使用方法——在子线程中更新界面,handler机制
- Android的消息机制,用Android线程间通信的Message机制,Android中Handler的使用方法——在子线程中更新界面,handler机制
- Android的消息机制,用Android线程间通信的Message机制,Android中Handler的使用方法——在子线程中更新界面,handler机制
- Android的消息机制,用Android线程间通信的Message机制,Android中Handler的使用方法——在子线程中更新界面,handler机制
- Android的消息机制,用Android线程间通信的Message机制,Android中Handler的使用方法——在子线程中更新界面,handler机制
- Android的消息机制,用Android线程间通信的Message机制,Android中Handler的使用方法——在子线程中更新界面,handler机制
- Android的消息机制,用Android线程间通信的Message机制,Android中Handler的使用方法——在子线程中更新界面,handler机制
- Android的消息机制,用Android线程间通信的Message机制,Android中Handler的使用方法——在子线程中更新界面,handler机制
- Android的消息机制,用Android线程间通信的Message机制,Android中Handler的使用方法——在子线程中更新界面,handler机制
- 路由原理
- Axis2: 学习笔记
- linux 查看磁盘空间大小
- 活动被以外回收,数据丢失了咋办
- LeetCode - Palindrome Number - Frequent
- 从子线程不能直接新建一个Handler对象来剖析android的Handler机制
- mysql 短信验证存储过程
- 窗口类结构体WNDCLASSEX介绍
- Wget命令
- 斯蒂芬森上分防守对方诗圣杜甫电视范德萨
- Emoji表情符号兼容方案
- 杭电 HDU 1196 Lowest Bit
- Linux查看系统配置常用命令
- 我的列表