Android Handler实现子线程与子线程、主线程之间通信
一、子线程向主线程传值:
首选在主线程里创建一个Handler
1 Handler mHandler = new Handler(){
2 @Override
3 public void handleMessage(Message msg) {
4 super.handleMessage(msg);
5 switch (msg.what) {
6 case 0:
7 //do something,refresh UI;
8 break;
9 default:
10 break;
11 }
12 }
13 };
- 然后开启一个子线程,在子线程里直接使用Handler发送消息即可
1 new Thread() {
2 public void run() {
3 Message message = new Message();
4 message.obj = "子线程发送的消息Hi~Hi";
5 mHandler .sendMessage(message);
6 };
7 }.start();
- 二、主线程向子线程里发送消息:
主线程向子线程发送消息的话,我们需要在子线程里初始化Looper,并在主线程里创建的Handler引用子线程的Looper(Handler中引用的是哪个线程的Looper,就在哪个线程里处理消息)
1 public class ThreadHandlerActivity extends Activity{
2 //创建子线程
3 class MyThread extends Thread{
4 private Looper looper;//取出该子线程的Looper
5 public void run() {
6
7 Looper.prepare();//创建该子线程的Looper
8 looper = Looper.myLooper();//取出该子线程的Looper
9 Looper.loop();//只要调用了该方法才能不断循环取出消息
10 }
11 }
12
13 private Handler mHandler;//将mHandler指定轮询的Looper
14
15 protected void onCreate(Bundle savedInstanceState) {
16 super.onCreate(savedInstanceState);
17 setContentView(R.layout.main);
18 thread = new MyThread();
19 thread.start();//千万别忘记开启这个线程
20 //下面是主线程发送消息
21 mHandler = new Handler(thread.looper){
22 public void handleMessage(android.os.Message msg) {
23 Log.d("当前子线程是----->",Thread.currentThread()+"");
24 };
25 };
26 mHandler.sendEmptyMessage(1);
27 }
28
29 }
其实这样就可以达到主线程向子线程发送消息了,然而当我们运行后发现程序会Crash掉,报了一个空指针,这是因为在Handler初始化的时候,thread.looper还没有初始化,所以会报空指针,这时我们可以让主线程等待一下子线程,也可以来一个while循环来判断thread.looper是否初始化完成。不过Android本身还提供了一个方法,那就是HandlerThread:
1 protected void onCreate(Bundle savedInstanceState) {
2 super.onCreate(savedInstanceState);
3 tv = new TextView(this);
4 tv.setText("Handler实验");
5 setContentView(tv);
6
7 //实例化一个特殊的线程HandlerThread,必须给其指定一个名字
8 HandlerThread thread = new HandlerThread("handler thread");
9 thread.start();//千万不要忘记开启这个线程
10 //将mHandler与thread相关联
11 mHandler = new Handler(thread.getLooper()){
12 public void handleMessage(android.os.Message msg) {
13 Log.d("当前子线程是----->", Thread.currentThread()+"");
14 };
15 };
16 mHandler.sendEmptyMessage(1);//发送消息
17 }
这时HandlerMessage所在的线程就是HandlerThread 的子线程。
然而HandlerThread 所创建处理的子线程里是不能重写Run()方法的,你写了以后,会发现,HandlerMessage不执行了,这时因为HandlerMessage本身实现了Run()方法,我们看一下内部实现:
1 @Override
2 public void run() {
3 mTid = Process.myTid();
4 Looper.prepare();
5 synchronized (this) {
6 mLooper = Looper.myLooper();
7 notifyAll();
8 }
9 Process.setThreadPriority(mPriority);
10 onLooperPrepared();
11 Looper.loop();
12 mTid = -1;
13 }
在源代码的第4行,进行了实例化自己的Looper,如果继续追踪源代码翻看其getLooper方法你会发现,如果一个Handler在与HandlerThread进行绑定时,发现Looper为空,Handler则会一直等待直到Looper被创建出来为止,然后才继续执行后续的代码。所以我们重写了HandlerThread的run方法,肯定就不会去创建Looper对象,那么绑定的Handler就会永远处于等待状态,自然而然就不会执行到HandlerMessage信息了。这也是为什么我们要使用HandlerThread这个特殊的线程,因为使用这个,我们不必关心多线程会混乱,Looper会为空等一系列问题,只要去关心我们要实现的逻辑就行了。
三、子线程和子线程之间通信:
其实子线程向子线程之间通信,其实就是在一个子线程中创建一个Handler,它的回调自然就在此子线程中,然后在另一个子线程中调用此handler来发送消息就可以了,不过记得写上Looper哦,下面看代码:
1 new Thread(new Runnable() {
2
3 @Override
4 public void run() {
5 String msg;
6 Looper.prepare();
7
8 childHandler = new Handler() {
9 @Override
10 public void handleMessage(Message msg) {
11 super.handleMessage(msg);
12
13 System.out.println("这个消息是从-->>" + msg.obj+ "过来的,在" + "btn的子线程当中" + "中执行的");
14
15 }
16
17 };
18 Looper.loop();//开始轮循
19
20 }
21 }).start();
- 其中 Looper.prepare()和Looper.loop()一定不要忘了写。
然后我们创建第二个子线程
1 new Thread(new Runnable() {
2
3 @Override
4 public void run() {
5 Looper loop = Looper.myLooper();
6 Message msg = childHandler.obtainMessage();
7 msg.obj = "btn2当中子线程";
8 childHandler.sendMessage(msg);
9 }
10 }).start();
Android Handler实现子线程与子线程、主线程之间通信的更多相关文章
- PYTHON线程知识再研习G--线程间通信Event
很多时候,线程之间会有互相通信的需要.常见的情形是次要线程为主要线程执行特定的任务,在执行过程中需要不断报告执行的进度情况.前面的条件变量同步已经涉及到了线程间的通信(threading.Condit ...
- C#中,子线程与主线程之间的通信是如何实现(转)
注: 项目中按照这个方法调试成功: 通常我们会有这种需求: 一个支持慢速设备的处理类,如网络通信.串口通信.打印等 此时经常需要将线程封装在类里面,让类支持异步处理,然后发布事件或者回调委托通知主线程 ...
- 【转】 Pro Android学习笔记(九十):了解Handler(4):Worker线程
目录(?)[-] worker线程小例子 小例子代码worker线程通过handler实现与主线程的通信 小例子代码继承Handler代码 小例子代码子线程的Runnable 文章转载只能用于非商业性 ...
- [Android学习笔记]子线程更新UI线程方法之Handler
关于此笔记 不讨论: 1.不讨论Handler实现细节 2.不讨论android线程派发细节 讨论: 子线程如何简单的使用Handler更新UI 问题: android开发时,如何在子线程更新UI? ...
- Android 使用handler实现线程间发送消息 (主线程 与 子线程之间)、(子线程 与 子线程之间)
keyword:Android 使用handler实现线程间发送消息 (主线程 与 子线程之间).(子线程 与 子线程之间) 相信大家平时都有使用到异步线程往主线程(UI线程)发送消息的情况. 本文主 ...
- android 子线程使用handle修改主线线程内容
1.子线程使用handle修改主线线程内容简单案例 1).activity_handle.xml <?xml version="1.0" encoding="utf ...
- 2017-11-29 由runnable说起Android中的子线程和主线程
1.首先纠正一个观点,就是runnable运行在子线程中是错误的观念.runnable只是创建了一个执行任务的对象,但是它本身并不会创建一个新的子线程,Runable只是给你接口让你实现工作线程的工作 ...
- 源码分析Android Handler是如何实现线程间通信的
源码分析Android Handler是如何实现线程间通信的 Handler作为Android消息通信的基础,它的使用是每一个开发者都必须掌握的.开发者从一开始就被告知必须在主线程中进行UI操作.但H ...
- Android线程间通信机制——深入理解 Looper、Handler、Message
在Android中,经常使用Handler来实现线程间通信,必然要理解Looper , Handler , Message和MessageQueue的使用和原理,下面说一下Looper , Handl ...
- OkHttp3几个简单的例子和在子线程更新UI线程的方法
okHttp用于android的http请求.据说很厉害,我们来一起尝尝鲜.但是使用okHttp也会有一些小坑,后面会讲到如何掉进坑里并爬出来. 首先需要了解一点,这里说的UI线程和主线程是一回事儿. ...
随机推荐
- hadoop实践01---hdfs分布式集群搭建与启动
一.hdfs集群组成结构
- Fabric-sdk-go操作Chaincode
因为工作的需要,最近了解了下如何通过sdk来操作Chaincode,本文是sdk使用时的一些操作总结. 在fabric网络启动过程中,一般分为"启动网络 -> 创建通道 -> 加 ...
- Map结构映射,避免每一个字段赋值
var query1 = (from fore in forecastShippingDate join ship in shipOutOfStock on fore.Id equals ship.F ...
- python随机种子seed的作用(强化学习常用到)
先上代码 import math import gym from gym import spaces, logger from gym.utils import seeding import nump ...
- 推荐系统[四]:精排-详解排序算法LTR (Learning to Rank)_ poitwise, pairwise, listwise相关评价指标,超详细知识指南。
0.前言召回排序流程策略算法简介 推荐可分为以下四个流程,分别是召回.粗排.精排以及重排: 召回是源头,在某种意义上决定着整个推荐的天花板: 粗排是初筛,一般不会上复杂模型: 精排是整个推荐环节的重中 ...
- LyScript 计算片段Hash并写出Excel
本案例将学习运用LyScript计算特定程序中特定某些片段的Hash特征值,并通过xlsxwriter这个第三方模块将计算到的hash值存储成一个excel表格,本例中的知识点可以说已经具备了简单的表 ...
- Java21 + SpringBoot3整合springdoc-openapi,自动生成在线接口文档,支持SpringSecurity和JWT认证方式
目录 前言 相关技术简介 OpenAPI Swagger Springfox springdoc swagger2与swagger3常用注解对比 实现步骤 引入maven依赖 修改配置文件 设置api ...
- PHP截取文章内容
<?php /** * 实现中文字串截取无乱码的方法. */ function getSubstr($string, $start, $length) { if (mb_strlen($stri ...
- MySQL 中 的 bit 类型,tinyint(1);
之前一直以为 mysql中没有 bit类型,需要使用 tinyint 来标识 bit.但是前端的实体类,不好控制,后来发现这些问题已经有了默认的统一设置,这样反而更好. 总结:MySQL中 使用布尔类 ...
- IntPtr 来把指针转换为 Int
由于想得到指针的值,这个时候,不能把指针强制转换为 integer 因为 integer 只适合32位的系统,64位的系统下,需要用 int64, 通过这个函数来转换,就可以屏蔽掉系统是32位 还是 ...