Handler系列之创建子线程Handler
上一篇我介绍了Handler机制的工作原理,默认情况下,ActivityThread类为我们创建的了主线程的Looper和消息队列,所以当你创建Handler之后发送消息的时候,消息的轮训和handle都是在ui线程进行的。这种情况属于子线程给主线程发消息,通知主线程更新ui...等,那么反过来,怎么才能让主线程给子线程发消息,通知子线程做一些耗时逻辑??
之前的学习我们知道,Android的消息机制遵循三个步骤:
1 创建当前线程的Looper
2 创建当前线程的Handler
3 调用当前线程Looper对象的loop方法
看过之前文章的朋友会注意到,本篇我特意强调了“当前线程”。是的之前我们学习的很多都是Android未我们做好了的,譬如:创建主线程的Looper、主线程的消息队列...就连我们使用的handler也是主线程的。那么如果我想创建非主线程的Handler并且发送消息、处理消息,这一系列的操作我们应该怎么办那???不怎么办、凉拌~~~什么意思???依葫芦画瓢,依然遵循上面的三步走,直接上代码!!!!
public class ChildThreadHandlerActivity extends Activity {
private MyThread childThread;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_handler);
childThread = new MyThread();
childThread.start();
Handler childHandler = new Handler(childThread.childLooper){//这样之后,childHandler和childLooper就关联起来了。
public void handleMessage(Message msg) {
};
};
}
private class MyThread extends Thread{
public Looper childLooper;
@Override
public void run() {
Looper.prepare();//创建与当前线程相关的Looper
childLooper = Looper.myLooper();//获取当前线程的Looper对象
Looper.loop();//调用此方法,消息才会循环处理
}
}
}
代码如上,我们依然循序Android的三步走战略,完成了子线程Handler的创建,难道这样创建完了,就可以发消息了么?发的消息在什么线程处理?一系列的问题,怎么办?看代码!!!运行上述代码,我们发现一个问题,就是此代码一会崩溃、一会不崩溃,通过查看日志我们看到崩溃的原因是空指针。谁为空???查到是我们的Looper对象,怎么会那?我不是在子线程的run方法中初始化Looper对象了么?话是没错,但是你要知道,当你statr子线程的时候,虽然子线程的run方法得到执行,但是主线程中代码依然会向下执行,造成空指针的原因是当我们new Handler(childThread.childLooper)的时候,run方法中的Looper对象还没初始化。当然这种情况是随机的,所以造成偶现的崩溃。
那怎么办?难道我们不能创建子线程Handler ???No!!!No!!!No!!!,你能想到的Android早就为我们实现好了,HandlerThread类就是解决这个问题的关键所在,看代码!!!
public class HandlerThreadActivity extends Activity {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_handler);
TextView textView = (TextView) findViewById(R.id.tv);
textView.setText("HandlerThreadActivity.class");
HandlerThread handlerThread = new HandlerThread("HandlerThread");
handlerThread.start();
Handler mHandler = new Handler(handlerThread.getLooper()){
@Override
public void handleMessage(Message msg) {
super.handleMessage(msg);
Log.d("HandlerThreadActivity.class","uiThread2------"+Thread.currentThread());//子线程
}
};
Log.d("HandlerThreadActivity.class","uiThread1------"+Thread.currentThread());//主线程
mHandler.sendEmptyMessage(1);
}
}
创建HandlerThread对象的时候,有个参数,是指定线程名字的。上面的代码不管运行多少次都不会奔溃!!!并且这种方法创建的handler的handleMessage方法运行在子线程中。所以我们可以在这里处理一些耗时的逻辑。到此我们完成了主线程给子线程发通知,在子线程做耗时逻辑的操作。
下面我们去看看源码,看看为什么使用HandlerThread就可以避免空指针那?
public Looper getLooper() {
if (!isAlive()) {
return null;
}
// If the thread has been started, wait until the looper has been created.
synchronized (this) {
while (isAlive() && mLooper == null) {
try {
wait();
} catch (InterruptedException e) {
}
}
}
return mLooper;
}
HandlerThread类的getLooper方法如上,我们看到当我们获取当前线程Looper对象的时候,会先判断当前线程是否存活,然后还要判断Looper对象是否为空,都满足之后才会返回给我Looper对象,否则处于等待状态!!既然有等待,那就有唤醒的时候,在那里那???我们发现HandlerThread的run方法中,有如下代码:
@Override
public void run() {
mTid = Process.myTid();
Looper.prepare();
synchronized (this) {
mLooper = Looper.myLooper();
notifyAll();
}
Process.setThreadPriority(mPriority);
onLooperPrepared();
Looper.loop();
mTid = -1;
}
说明了什么那???HandlerThread类start的时候,Looper对象就初始化了,并唤醒之前等待的。所以HandlerThread很好的避免了之前空指针的产生。所以以后要想创建非主线程的Handler时,我们用HandlerThread类提供的Looper对象即可。
至此,前三篇我们讲了Handler的使用、工作原理、创建子线程Handler。下一篇我会讲使用Handler引起的内存泄漏的解决办法。
Handler系列之创建子线程Handler的更多相关文章
- 关于Handler的理解,子线程不能更新UI的纠正和回调的思考
开发Android这么久了,总会听到有人说:主线程不能访问网络,子线程不能更新UI.Android的主线程的确不能长时间阻塞,但是子线程为什么不能更新UI呢?今天把这些东西整理,顺便在子线程更新UI. ...
- 通过类创建子线程&同步锁
一.通过类创建子线程 import threading class MyThread(threading.Thread): def __init__(self,num): threading.Thre ...
- C# WebService中任务处理线程创建子线程后
protected void WriteLog(string message) { lock (lockObject) { var file = System.IO.File.AppendText(& ...
- Handler主线程和子线程相通信
//创建主线程的handlerprivate Handler handler = new Handler(){ @Override public void handleMessage(Message ...
- C#创建子线程,子线程使用委托更新控件
一.背景 由于在窗体程序中通过点击一个button按键后需要更新TreeView控件的内容,由于等待时间比较长,主程序无法一起在那边等待,需要去处理其它的事情,所以就需要创建新的子线程来处理.因为主线 ...
- Handler系列之内存泄漏
本篇简单的讲一下平常使用Handler时造成内存泄漏的问题. 什么是内存泄漏?大白话讲就是分配出去的内存,回收不回来.严重会导致内存不足OOM.下面来看一下造成内存泄漏的代码: public clas ...
- 在子线程中new Handler报错--Can't create handler inside thread that has not called Looper.prepare()
在子线程中new一个Handler为什么会报以下错误? java.lang.RuntimeException: Can't create handler inside thread that has ...
- [Android学习笔记]子线程更新UI线程方法之Handler
关于此笔记 不讨论: 1.不讨论Handler实现细节 2.不讨论android线程派发细节 讨论: 子线程如何简单的使用Handler更新UI 问题: android开发时,如何在子线程更新UI? ...
- 【转】在子线程中new Handler报错--Can't create handler inside thread that has not called Looper.prepare()
在子线程中new一个Handler为什么会报以下错误? java.lang.RuntimeException: Can't create handler inside thread that has ...
随机推荐
- 理解加密算法(三)——创建CA机构,签发证书并开始TLS通信
接理解加密算法(一)--加密算法分类.理解加密算法(二)--TLS/SSL 1 不安全的TCP通信 普通的TCP通信数据是明文传输的,所以存在数据泄露和被篡改的风险,我们可以写一段测试代码试验一下. ...
- JSON.parse()和JSON.stringify()
1.parse 用于从一个字符串中解析出json 对象.例如 var str='{"name":"cpf","age":"23&q ...
- OpenCASCADE BRep Projection
OpenCASCADE BRep Projection eryar@163.com 一网友发邮件问我下图所示的效果如何在OpenCASCADE中实现,我的想法是先构造出螺旋线,再将螺旋线投影到面上. ...
- Velocity初探小结--velocity使用语法详解
做java开发的朋友一般对JSP是比较熟悉的,大部分人第一次学习开发View层都是使用JSP来进行页面渲染的,我们都知道JSP是可以嵌入java代码的,在远古时代,java程序员甚至在一个jsp页面上 ...
- maven-sprigmvc-mybatis配置
pom.xml配置 <?xml version="1.0"?> <project xsi:schemaLocation="http://maven.ap ...
- hibernate的基本xml文件配置
需要导入基本的包hibernate下的bin下的required和同bin下optional里的c3p0包下的所有jar文件,当然要导入mysql的驱动包了.下面需要注意的是hibernate的版本就 ...
- 自建git node pm2 (不赘述,就说遇见的问题)
//======================[git]部分 主题部分还是按照网上的办法进行安装. 安装的话 分为两个办法(一个是yum (contos办法) 或者sudo(ubuntu办法) ...
- Oracle常用SQL函数整理
--返回ASCII码select ASCII('A') "A的ASCII码" ,ASCII('a') "a的ASSCII码" from dual ; --反向 ...
- wireshark 相关提示
Packet size limited during capture 提示说明标记的包没有抓全,在某些操作系统中,默认只抓96个字节,tcpdump中有"-s"参数可用于 ...
- 第11章 Linux服务管理
1. 服务分类 (1)Linux的服务 ①Linux中绝大多数的服务都是独立的,直接运行于内存中.当用户访问时,该服务直接响应用户,其好处是服务访问响应速度快.但不利之处是系统中服务越多,消耗的资源越 ...