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,一经查实,立即删除!

相关文章

CENTOS6.4安装vnc-server

yum install tigervnc-servervi /etc/sysconfig/vncservers只需要两类内容就可以了&#xff0c;一个是定义用户&#xff0c;一个是定义用户登录情况&#xff1a;参考&#xff1a;VNCSERVERS"1:root 2:river"VNCSERVERARGS[1]"-geometry 800x600 -nolisten tcp&q…

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

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

sql server 之函数小技巧 整数类型为空是用空字符串替代实现

1、判空函数 说明&#xff1a;使用指定的替换值替换 NULL。 语法&#xff1a;ISNULL ( check_expression , replacement_value ) 参数&#xff1a; check_expression&#xff1a;将被检查是否为 NULL 的表达式。check_expression 可以为任何类型。 replacement_value&#xff1…

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

在日常生活中&#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…

Android之调用系统分享

1、调用系统分享关键代码 private void shareImage() {Intent intent = new Intent(Intent.ACTION_SEND); intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);intent.putExtra(Intent.EXTRA_STREAM, Uri.fromFile(new File("sdcard/screenshot.png")));intent.setTyp…

hdu4750Count The Pairs(最小生成树找瓶颈边)

1 /*2 题意&#xff1a;就是给你一个图&#xff0c;图的每两个点都有多条路径&#xff0c;每一条路径中都有一条最大边&#xff0c;3 所有最大边的最小边&#xff08;也就是瓶颈边&#xff09;就是这两点之间的val值&#xff01;然后给你一个值f&#xff0c;4 问有多少…

服务器的响应一直一直发送不过去,zeroRPC:在发送响应后继续运行进程

我使用Python2.7和zeroRPC使客户机和服务器通信。我希望客户端向服务器发送一个请求&#xff0c;我希望服务器发送一个响应以确认它已收到请求。但是我希望服务器对该请求执行一些繁重的计算。这些计算将花费数小时&#xff0c;并且不会产生任何响应&#xff0c;因此客户机不应…

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

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

【机房收费系统】多么痛的领悟

这次机房收费系统&#xff0c;是全部的项目中&#xff0c;自己完毕的最不惬意的了。 时间之长。效率之慢。一開始。就感觉无从下手&#xff0c;但总会相信自己能慢慢的进入状态。最终有机会自己练练手了。也自觉得之前自己设计模式学的还不错。也最终有机会能自己想想设计模式了…

linux(windows)之svn重定向地址

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

简单的邮箱格式校验方式

简单的邮箱格式校验方式Intro前段时间有一个验证邮箱格式的小需求&#xff0c;然后突然发现了一种非常简单的邮箱格式判断方式Implement直接来看实现public static bool IsEmailAddress(string email) {if (string.IsNullOrWhiteSpace(email))return false;var symbolIndex em…

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;&#…

Android之项目全部能正常登录但是部分资源没有显示成功的解决办法

1、问题 自己写的项目&#xff0c;PC端没有问题&#xff0c;移动端有问题 第一个问题 部分能登录&#xff0c;一部分不能登录 第二个问题 解决第一个问题后&#xff0c;全部能登录&#xff0c;但是登录之后部分资源显示不成功&#xff0c;部分可以 2、原因 第一个问题的原…

ASP.NET Core 6 的性能改进

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

(转载)在服务器上排除问题的头5分钟

尽可能搞清楚问题的前因后果 不要一下子就扎到服务器前面&#xff0c;你需要先搞明白这台服务器有多少已知的情况&#xff0c;还有故障的具体情况&#xff0c;不然你很有可能是在无的放矢必须要搞清楚的问题&#xff1a;故障的表现是什么&#xff1f;无响应&#xff1f;报错&am…

wikioi 1034 家 实时动态的网络流量(费用流)

因为随着时间的推移。网络侧变得&#xff0c;因此&#xff0c;常见的网络流量也解决不了这个问题&#xff0c;。如果T毕竟运输时间。为此。我们可以基于时间分割点&#xff0c;所有的点将被分割为T点。 对于每一个点&#xff0c;下一次甚至一个容量为本人INF边缘&#xff0c;费…