handlerThread使用场景分析及源码解析
来源:互联网 发布:店铺做账用那个软件 编辑:程序博客网 时间:2024/06/05 16:01
这篇博客将结合Android7.0源码,解析HandlerThread的使用场景及实现原理。
1.为什么要有handlerThread组件出现?
在Android中我们使用消息机制进行线程间的消息传递,如果是向主线程传递消息,我们构造主线程的handler,并使用他发送消息。使用起来还是很方便的。但是如果是要子线程传递消息,就需要构建子线程的handler. 这样使用起来就比较麻烦了!比如下面这样:
public class Main2Activity extends AppCompatActivity { @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main2); new Thread(new Runnable() { @Override public void run() { Looper.prepare(); Handler handler=new Handler(){ @Override public void handleMessage(Message msg) { super.handleMessage(msg); //处理子线程的消息 } }; Looper.loop(); } }).start(); }}
我们得在子线程中构建Looper,并调用Looper的loop方法才能正确的构建出子线程的handler对象。这样用也没什么,但代码看着实在是很不舒服呀。 所以android给我们提供了HandlerThread组件,封装了子线程中构建looper的繁琐操作。
2.HandlerThread的使用场景
在介绍HandlerThread之前,我们先想一个它的使用场景,通过使用场景,结合使用示例。我们才能在分析它的源码的时候有一个好的切入点,而且还可以加深我们对于handlerThread的一些印象; 可以想象一下这样的一个场景,例如我之前研发了一款股票交易软件,因为股票的行情数据都是实时变化的。所以我们软件需要每隔一定时间向服务器请求行情数据。
代码示例如下:
public class MainActivity extends AppCompatActivity { SimpleDateFormat df = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");//设置日期格式 TextView updateTimeTv; Handler mUIHandler=new Handler(){ @Override public void handleMessage(Message msg) { //更新ui updateTimeTv.setText((String)msg.obj); //1秒后再次请求服务器,并更新数据 timeMessagehandler.sendEmptyMessageAtTime(0,1000); } }; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); updateTimeTv = (TextView)findViewById(R.id.tv); initThreadHandler(); } HandlerThread handlerThread; Handler timeMessagehandler; private void initThreadHandler() { //构建HandlerThread handlerThread=new HandlerThread("updateTimeThread"); //启动handler handlerThread.start(); //构建子线程的handler对象 timeMessagehandler=new Handler(handlerThread.getLooper()){ @Override public void handleMessage(Message msg) { //请求服务端时间 try { //模拟耗时请求 Thread.sleep(3000); } catch (InterruptedException e) { e.printStackTrace(); } //网络请求成功,通过主线程更新ui Message message=Message.obtain(); message.obj= df.format(new Date()); mUIHandler.sendMessage(message); System.out.println("handlerTimeMessage"+Thread.currentThread().getName()); } }; //向子线程发送消息,通知它发送网络请求 timeMessagehandler.sendEmptyMessage(0); }}
我们分析一下上面的代码实现,一步一步来解析HandlerThread的使用,略过mUIHandler和view的初始化代码不表。我们可以看到上面的代码先构建了一个HandlerThread对象,然后调用了它的start方法。 这里我们可以提前剧透一下。HandlerThread对象对象其实继承了Thread对象。所以调用它的start方法就会执行它的run方法。 然后我们用handlerThread.getLooper()方法构建一个timeMessagehandler对象。 从上面的代码看timeMessagehandler对象的handleMessage中可以执行耗时操作,也就说明该方法是执行在子线程中的。那handlerThread.getLooper()方法所获取的方法也就肯定是子线程的Looper对象了。 这部分不清楚的可以看我另一篇文章,android消息机制源码分析http://blog.csdn.net/nightcurtis/article/details/77539971。 所以我们就可以timeMessagehandler对象向子线程发送消息执行耗时任务, 然后通过主线程的mUIHandler对象发消息处理ui的显示。 这些代码就太简单这里就不说了。 结合这段使用代码实例,我们可以知道我们下面这短短的3行代码就能够完成之前构建线程,初始化looper等等操作才能完成的构造子线程handler的这样一个需求。这是怎么做到的呢!
handlerThread=new HandlerThread("updateTimeThread"); //启动handler handlerThread.start(); //构建子线程的handler对象 timeMessagehandler=new Handler(handlerThread.getLooper());
3.HandlerThread的源码解析
通过HandlerThread的使用场景解析我们知道通过短短3行代码就可以完成之前初始化looper,构建handler对象,并调用loop才能正确创建的子线程handler对象。 这里面的秘密是什么呢? 结合HandlerThread的源码。我们来解析一下:
public class HandlerThread extends Thread { int mPriority; int mTid = -1; Looper mLooper; public HandlerThread(String name) { super(name); mPriority = Process.THREAD_PRIORITY_DEFAULT; } public HandlerThread(String name, int priority) { super(name); mPriority = priority; } protected void onLooperPrepared() { } @Override public void run() { mTid = Process.myTid(); Looper.prepare(); synchronized (this) { mLooper = Looper.myLooper(); notifyAll(); } Process.setThreadPriority(mPriority); onLooperPrepared(); Looper.loop(); mTid = -1; } 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的源码很简单。HandlerThread继承了Thread对象,所以我们构造HandlerThread对象的时候就是构建了一个子线程对象。 调用线程对象的start方法,就会执行HandlerThread的run函数。 我们看到在run方法中有 Looper.prepare(),Looper.loop()两个方法。其实和我们在子线程中构建looper的方法完全相同。 真正值得注意的是,发现在run方法中和looper的getLooper中有一个线程通信的处理。 这个是为什么呢? 想想之前我们是主线程中先构建handlerThread对象,然后调用它的start方法,去初始化looper对象。 然后就调用handlerThread的getLooper()方法去初始化一个子线程的Handler对象。 我们知道 handlerThread的start方法是执行在子线程中的,而handlerThread的getLooper()方法是执行在主线程中的。我们不能确认他们谁先执行,如果是getLooper()方法先执行,而这个时候子线程的looper还没有创建。构建handler就会抛出异常。 所以我们需要确保getLooper()方法在Looper创建成功后执行。所以在这里添加了线程通信的处理。
4.总结
其实分析源码后我们能够发现HandlerThread的源码特别简单,但我们解析它的源码不止是为了分析它的源码。更重要的是要学习它的一下封装的思想。 还有就是了解它的原理后,以后遇到使用了HandlerThread的组件心里上会有征服感。哈哈。 比如了解了HandlerThread的原理后再去看IntentService的原理。 真是不能再简单了。 有么有!!
- handlerThread使用场景分析及源码解析
- Android 进阶15:HandlerThread 使用场景及源码解析
- HandlerThread源码分析及使用
- android源码解析(6)--HandlerThread分析及使用对比
- HandlerThread使用&源码解析
- Android中HandlerThread的使用及源码解析
- HandlerThread使用和源码解析
- Android Handler 四个使用实例 及HandlerThread的使用,androidhandler实例,HandlerThread 源码分析
- 从HandlerThread 的使用来分析HandlerThread的源码
- HandlerThread 使用及其源码完全解析
- Android多线程:HandlerThread使用&源码解析
- HandlerThread 的使用及其源码完全解析
- 【android】HandlerThread的使用及源码剖析
- 【android】HandlerThread的使用及源码剖析
- Android HandlerThread 使用介绍及简单解析
- Volley源码解析使用方式和使用场景分析
- Android HandlerThread使用及原理分析
- HandlerThread源码解析
- Anonymous Inner Class(匿名内部类)是否可以继承其它类?是否可以实现接口?【Java面试题】
- ARM分类
- 自用整理资源插件
- mac远程连接----->>>teamviewer
- idea创建spring
- handlerThread使用场景分析及源码解析
- iOS 网络
- Android内存泄漏的八种可能
- 实用前端JS工具类(验证,AJAX请求封装,分页插件等)真实项目使用
- Linux基本命令
- ecshop添加类似于精品,新品,热销的模块
- 获取元素方式
- 常用正则表达式大全
- 自我突破