Android之HandlerThread源码分析和简单使用(主线程和子线程通信、子线程和子线程通信)

1、先熟悉handler方式实现主线程和子线程互相通信方式,子线程和子线程的通信方式

      如果不熟悉或者忘记了,请参考我的这篇博客     Android之用Handler实现主线程和子线程互相通信以及子线程和子线程之间的通信     http://blog.csdn.net/u011068702/article/details/75577005

 

 

 

2、贴上简单HandlerThread简单使用(主线程和子线程通信、子线程和子线程通信)的例子

1、activity_main.xml文件

 

<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"xmlns:tools="http://schemas.android.com/tools"android:layout_width="match_parent"android:layout_height="match_parent"android:paddingBottom="@dimen/activity_vertical_margin"android:paddingLeft="@dimen/activity_horizontal_margin"android:paddingRight="@dimen/activity_horizontal_margin"android:paddingTop="@dimen/activity_vertical_margin"tools:context="com.example.handler.MainActivity1" ><Buttonandroid:id="@+id/button1"android:layout_width="wrap_content"android:layout_height="wrap_content"android:text="ParentToChile" /><Buttonandroid:layout_below="@+id/button1"android:id="@+id/button2"android:layout_width="wrap_content"android:layout_height="wrap_content"android:text="ChileToParent" /><Buttonandroid:layout_below="@+id/button2"android:id="@+id/button3"android:layout_width="wrap_content"android:layout_height="wrap_content"android:text="ChileToChile" /></RelativeLayout>

 

 

 

2、MainActivity.java文件

 

package com.example.handler;import android.os.Bundle;
import android.os.Handler;
import android.os.HandlerThread;
import android.os.Looper;
import android.os.Message;
import android.support.v7.app.ActionBarActivity;
import android.util.Log;
import android.view.View;
import android.view.View.OnClickListener;
import android.widget.Button;public class MainActivity extends ActionBarActivity {public static final String TAG = "HandlerTest";public HandlerThread mHandlerThread;public Handler mChileHandler;public Handler mHandlerCToP = new Handler(){@Overridepublic void handleMessage(Message msg) {super.handleMessage(msg);int id =  (int) Thread.currentThread().getId();Log.d(TAG, "mHandlerCToP currentThread id is:" + id);}};public Button mButtonPtoC;public Button mButtonCtoP;public Button mButtonCtoC;public Handler mHandler = new Handler();public Handler mHandlerCtoC = null;@Overrideprotected void onCreate(Bundle savedInstanceState) {super.onCreate(savedInstanceState);setContentView(R.layout.activity_main);int id =  (int) Thread.currentThread().getId();Log.d(TAG, "onCreate currentThread id is:" + id);initUIAndThread();}public void initUIAndThread() {mHandlerThread = new HandlerThread("chenyu");mHandlerThread.start();mHandler = new Handler(mHandlerThread.getLooper()) {@Overridepublic void handleMessage(Message msg) {int id =  (int) Thread.currentThread().getId();Log.d(TAG, "initThread() mHandler handleMessage currentThread id is:" + id);switch(msg.what) {case 0:mHandlerCToP.post(new Runnable(){@Overridepublic void run() {int id =  (int) Thread.currentThread().getId();Log.d(TAG, "initThread() mHandlerCToP post currentThread id is:" + id);mButtonPtoC.setText("chenyu");}});break;case 1:mHandlerCToP.post(new Runnable(){@Overridepublic void run() {int id =  (int) Thread.currentThread().getId();Log.d(TAG, "initThread() mHandlerCToP post currentThread id is:" + id);mButtonCtoC.setText("chenyu");}});default:break;}}};mButtonPtoC = (Button)findViewById(R.id.button1);mButtonCtoP = (Button)findViewById(R.id.button2);mButtonCtoC = (Button)findViewById(R.id.button3);mButtonPtoC.setOnClickListener(new OnClickListener(){@Overridepublic void onClick(View v) {int id =  (int) Thread.currentThread().getId();Log.d(TAG, "mButtonPtoC currentThread id is:" + id);Log.d(TAG, "mHandlerPToc msg.what is 0");mHandler.sendEmptyMessage(0);}});mButtonCtoP.setOnClickListener(new OnClickListener(){@Overridepublic void onClick(View v) {int id =  (int) Thread.currentThread().getId();Log.d(TAG, "mButtonCtoP currentThread id is:" + id);Log.d(TAG, "mHandlerPToc msg.what is 0");mHandlerCToP.sendEmptyMessage(0);}});mButtonCtoC.setOnClickListener(new OnClickListener(){@Overridepublic void onClick(View v) {new Thread(new Runnable(){@Overridepublic void run() {int id =  (int) Thread.currentThread().getId();Log.d(TAG, "mButtonCtoC currentThread id is:" + id);Log.d(TAG, "mHandlerCToc msg.what is 1");mHandler.sendEmptyMessage(1);}}).start();}});}@Overrideprotected void onDestroy() {super.onDestroy();mHandlerThread.quit();}    
}

 

 

 

 

 

 

 

 

3、简单分析例子

   1)、原始页面效果

        

    2)、控制台初始化打印的线程ID

       

       分析:在onCreate方法里面打印的主线程的Id为1,有3个按钮,分别是主线程向子线程发消息,子线程向主线程发消息,子线程和子线程发送消息,我们一开始就是对HandlerThread进程初始化,其实它就是一个线程,后面会分析,然后执行了start方法,我们把HandlerThread的looper对象传递给了Handler,之前的文章已分析,一个线程只能有一个looper对象,Handler拥有了HandlerThread的looper对象,就相当于这个Handler在HandlerThread线程同样的线程Id,可以理解为Handler 在子线程里面构建,为什么我这里还有其它的Handler构建,因为想搞清楚在哪里构建属于哪个线程以及子线程的handler是否可以更新UI,主线程构建的handler是否可以更新UI,

    3)、依次点击3个按钮后控制台打印的日志

       

     我们可以看到在onCreate方法里面始化handler的时候传递了一个HandlerThread的looper对象,点击第一个按钮后后没有开启线程,当前线程依然是主线程,handler发送了一个消息,然后初始化的handlMessage收到消息了,也就完成了主线程到子线程的通信,当收到消息的时候,我们发现线程的id是6314,所以这个时候虽然是在onCreate里面构建的handler里面的handlerMessage方法,但是线程Id是和HandlerThread线程Id是一样的,然后初始化handler去更新界面,我们代码是用mHandlerCtopP去更新的,因为它的初始化是在主线程构建的,所以可以post可以更新UI,但是这个时候用拥有HandlerThread的looper对象的handler更新界面就会出问题,和子线程里面的handler去更新界面异常一样,如下图

 

然后点击第二个按钮,是现实子线程向主线程通信,我们发现点击时间里面的线程Id,和handler收到消息的 handleMessage方法里面的线程id, 都是一样,和主线程Id一样,所以我们可以用这个handler直接post来更新UI,

点击第三个按钮,是实现子线程和子线程的通信,执行点击方法,我们开启了一个线程,自然线程Id会和主线程的不一样,为6318, handler收到消息的 handleMessage方法里面的线程id为6314,所以这里可以理解为为子线程线程里面构建了handler,然后用主线程构建的handler更新ui

 

   4)、依次点击3个按钮后手机效果

     

 

 

 

 

4、HandlerThread.java源码分析

    1、上源代码

     

package android.os;/*** Handy class for starting a new thread that has a looper. The looper can then be * used to create handler classes. Note that start() must still be called.*/
public class HandlerThread extends Thread {int mPriority;int mTid = -1;Looper mLooper;public HandlerThread(String name) {super(name);mPriority = Process.THREAD_PRIORITY_DEFAULT;}/*** Constructs a HandlerThread.* @param name* @param priority The priority to run the thread at. The value supplied must be from * {@link android.os.Process} and not from java.lang.Thread.*/public HandlerThread(String name, int priority) {super(name);mPriority = priority;}/*** Call back method that can be explicitly overridden if needed to execute some* setup before Looper loops.*/protected void onLooperPrepared() {}@Overridepublic void run() {mTid = Process.myTid();Looper.prepare();synchronized (this) {mLooper = Looper.myLooper();notifyAll();}Process.setThreadPriority(mPriority);onLooperPrepared();Looper.loop();mTid = -1;}/*** This method returns the Looper associated with this thread. If this thread not been started* or for any reason is isAlive() returns false, this method will return null. If this thread * has been started, this method will block until the looper has been initialized.  * @return The looper.*/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;}public boolean quit() {Looper looper = getLooper();if (looper != null) {looper.quit();return true;}return false;}public boolean quitSafely() {Looper looper = getLooper();if (looper != null) {looper.quitSafely();return true;}return false;}/*** Returns the identifier of this thread. See Process.myTid().*/public int getThreadId() {return mTid;}
}


1、我们知道这个类在android.os目录下,然后继承了Thread,也就是一个线程

 

2、构造方法会传一个字符串,这里可以随便写,只作为一个标识而已,初始化的时候会调用start方法,然后会执行run()方法

 

    @Overridepublic void run() {mTid = Process.myTid();Looper.prepare();synchronized (this) {mLooper = Looper.myLooper();notifyAll();}Process.setThreadPriority(mPriority);onLooperPrepared();Looper.loop();mTid = -1;}


先执行了Looper,prepare(),然后给当前mLooper赋值,然后进行Looper.loop(),进行轮寻,这个代码和标准的子线程用handler的方式差不多,也可以理解为这种方式的封装,所以才能显示子线程和子线程和主线程之间的通信,原理都是一样。

 

3、getLooper()中有个wait(),这有什么用呢?因为的mLooper在一个线程中执行创建,而我们的handler是在UI线程中调用getLooper()初始化的,必须等到mLooper创建完成,才能正确的返回。getLooper();wait(),notify()就是为了解决这两个线程的同步问题。

 

4、这里有个退出的方法是

 

    public boolean quit() {Looper looper = getLooper();if (looper != null) {looper.quit();return true;}return false;}


我之前写代码的时候,以为停止线程就调用了,mHandlerThread.stop()方法,后面没发现什么问题,直到我们有个功能需要,从控制台下发消息让手机恢复默认出场,函数执行到了这里,导致进程崩溃了,然后就发现这里有问题,需要调用mHandlerThread.quit()方法正常退出。

 

 

 

 

5、总结

      有时还需要频繁更新UI,或则主线程向子线程通信,以及子线程和子线程经常通信的时候,我们可以使用HandlerThread,如果哪里没说清楚,或则讲得有问题,欢迎点评

 

 

 

 

 

 

         

     

 

 

 

 

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/290795.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

Avalonia跨平台入门第八篇之控件的拖放

在前面分享的几篇中咱已经玩耍了Popup、ListBox多选、Grid动态分、RadioButton模板,过程还算顺利;今天接着把把ListBox中的Item拖放到Cavans中(基于官方的Samples实现的);直接看效果吧:1、ListBox中PointerPressed、DragOver事件:2、Canvas中的Drop事件:3、控件的移除无非就是通…

车牌识别系统连不上服务器怎么办,车牌识别系统出现故障的解决方法有哪些?...

在日常生活中&#xff0c;各个小区、商业广场、酒店、办公楼等等地方出入口装置有车牌识别系统&#xff0c;有此可见车牌识别系统的使用越来越广泛。停车场办理系统的使用给人们带来便利的同时&#xff0c;也常常会出现一些小问题。今天小编就给大家分享一下车牌识别系统遇到故…

霍夫变换

作者&#xff1a;桂。 时间&#xff1a;2017-04-24 12:18:17 链接&#xff1a;http://www.cnblogs.com/xingshansi/p/6756305.html 前言 今天群里有人问到一个图像的问题&#xff0c;但本质上是一个基本最小二乘问题&#xff0c;涉及到霍夫变换&#xff08;Hough Transform&a…

ASP.NET Core 实现基于 ApiKey 的认证

ASP.NET Core 实现基于 ApiKey 的认证Intro之前我们有介绍过实现基于请求头的认证&#xff0c;今天来实现一个基于 ApiKey 的认证方式&#xff0c;使用方式参见下面的示例Sample注册认证服务services.AddAuthentication().AddApiKey(options >{options.ApiKey "123456…

白平衡自己主动(AWB)算法---2,颜色计算

本文说明了白平衡算法估计当前场景的色温过程. 色温计算的原理并不复杂,但要做到,还是一道&#xff0c;认真做好每一步,这需要大量的测试,和算法一直完好. 关于该过程首先简要: 1, 取的图像数据,并划分MxN块,如果是25x25,并统计每一块的基本信息(,白色像素的数量及R/G/B通道的分…

linux(windows)之svn重定向地址

1、问题 svn下载的项目路径需要换&#xff0c;也就是下面的URL:SVN:// 需要修改 2、解决办法 linux平台 svn switch --relocate oldSvnPath newSvnPath windows平台 右击项目 TortoiseSVN->Relocate 然后修改就行

Ubuntu14.04LST安装weblogic11g

1:下载链接http://download.oracle.com/otn/nt/middleware/11g/wls/1036/wls1036_generic.jar 2:进行安装&#xff08;前提已经安装好JDK&#xff09; yy:~/my_download$ java -d64 -Xmx1024m -jar wls1036_generic.jar Extracting 0%.......................................…

服务器连接不稳定fifa,fifa服务器链接异常

fifa服务器链接异常 内容精选换一换获取登录密码Windows操作系统在创建时只能选择密钥登录&#xff0c;需要先将密钥文件解析为密码&#xff0c;参考链接&#xff1a;获取Windows裸金属服务器的密码Windows操作系统在创建时只能选择密钥登录&#xff0c;需要先将密钥文件解析为…

并发编程总结4-JUC-REENTRANTLOCK-2(公平锁)

内容包括&#xff1a;1、ReentrantLock函数分析2、ReentrantLock公平锁源码&#xff0d;&#xff0d;&#xff0d;&#xff0d;&#xff0d;&#xff0d;&#xff0d;&#xff0d;&#xff0d;&#xff0d;&#xff0d;&#xff0d;&#xff0d;&#xff0d;&#xff0d;&#…

ASP.NET Core 6 的性能改进

受到 由Stephen Toub 发布的关于 .NET 性能的博客的启发&#xff0c;我们正在写一篇类似的文章来强调ASP.NET Core 在6.0 中所做的性能改进。基准设置我们整个过程中大部分的实例使用的是BenchmarkDotNet。在此链接上提供了repo&#xff0c;其中包括本文中使用的大多数基准。Be…

华为服务器只显示一个下划线,华为官方解释:为什么鸿蒙系统logo下面会有一条下划线...

HarmonyOS 的 Logo 中为什么有一横&#xff1f;为什么这一横偏偏是蓝色&#xff1f;HarmonyOS 的字体设计又藏着什么奥秘&#xff1f;6月10日晚&#xff0c;华为官方微博对鸿蒙系统LOGO设计寓意&#xff0c;作出了官方科普。下面就来为你一一解答在现代汉语中“旦”字与鸿蒙OS中…

ORACLE利用STANDBY端RMAN备份进行数据恢复

这里记录一下流程&#xff0c;有我和同事问心进行测试 dataguard主库和物理备库主要是controlfile文件有区别&#xff0c;用restore可以查看含有primary,standby关键字 RMAN> restore ; RMAN-00571: RMAN-00569: ERROR MESSAGE STACK FOLLOWS RMAN-00571: RMAN-00558: e…

腾讯急招多名.NET Core,5年30k!

金三银四跳槽季&#xff0c;腾讯急招5年左右.NET Core高级开发岗&#xff0c;基本月薪能到30k&#xff0c;心动吗&#xff1f;这里推荐个.NET跳槽大厂交流群&#xff0c;有技术交流&#xff0c;有面经分享&#xff0c;还有内推通道&#xff0c;据说有一定几率降低学历要求&…

perl学习笔记——目录操作

在目录书中移动 chdir 操作副改变当前的工作目录。它和shell中cd命令类似&#xff1a; chdir ‘/etc’ or die “cannot chdir to /etc:$1”; 注意&#xff1a;工作目录不能更改的&#xff0c;也就是说Perl程序返回后一定会回到所在的工作目录。 如果调用chdir时不加参数&#…

凌动服务器系列,凌动也能造服务器?超微又出怪异新品

【IT168 专稿】上月初举行的英特尔春季IDF上&#xff0c;记者看到超微展示了采用独特设计的2U Twin系列高密度Nehalem服务器&#xff0c;该服务器采用了全冗余设计&#xff0c;包括主板在内的所有部件都有两个互为备份。可以说超微一直以来都以自身独特的设计理念和大胆的实践拓…

C语言——关于数据在内存中存储的练习

大家好&#xff0c;我是残念&#xff0c;希望在你看完之后&#xff0c;能对你有所帮助&#xff0c;有什么不足请指正&#xff01;共同学习交流 本文由&#xff1a;残念ing原创CSDN首发&#xff0c;如需要转载请通知 个人主页&#xff1a;残念ing-CSDN博客&#xff0c;欢迎各位→…

Avalonia跨平台入门第九篇之控件置顶和置底

在前面分享的几篇中咱已经玩耍了Popup、ListBox多选、Grid动态分、RadioButton模板、控件的拖放效果;今天趁着有时间接着对拖放到Canvas上的控件进行置顶和置底切换的效果,最终实现的效果如下图:关于置顶和置底的实现代码:接下来的文章中我会再来分享在Canvas上控件的锁定效果;…

C/C++之常用字符串比较总结

1、std::string比较 我们一般用str1.compare(str2) 0来实现 2、const char* 的比较 我们一般用strcmp(p1, p2) 0来实现 3、代码 4、结果 str1 str4 str5 is null p1 p3

【C#/.NET】控制台上动态构建中间件管道

如上图所示&#xff1a;我们将会在下面文章上一步一步变形实现出这样的功能。一、傻瓜式执行演示首先建立控制台项目&#xff0c;创建Begin() FirstMiddleware() SecondMiddleware() End() 三个函数1 /// <summary>2 /// 开始执行前3 /// </summ…

SON Web Token设计单点登录系统

2019独角兽企业重金招聘Python工程师标准>>> 上次在《JSON Web Token - 在Web应用间安全地传递信息》中我提到了JSON Web Token可以用来设计单点登录系统。我尝试用八幅漫画先让大家理解如何设计正常的用户认证系统&#xff0c;然后再延伸到单点登录系统。 如果还没…