Android组件通信——消息机制(二十六)
1. 消息机制
1.1 知识点
(1)掌握Message、Handler、Looper类的使用以及消息的传递;
(2)可以通过消息机制动态取得信息;
1.2 具体内容
对于android的消息机制,我们主要要使用Java中线程的一些知识:
线程:线程是进程一个细的划分,一个进程可以存在多个线程。Java中实现多线程的手段有两种:
·继承Thread类
·实现Runnable接口
在开发中,使用第二种方式实现多线程是优先选择的,主要继承Thread实现的多线程有一下两个问题:
·Java单继承的局限
·使用Runnable可以实现数据的共享
但是使用第二种方式实现的多线程,在线程启动的时候也必须使用Thread进行线程的启动。
主线程一般在android中成为UI线程,就是一个界面显示,那么这种就是主线程,而子线程就是利用那些实现了Runnable接口的线程的操作类。
对于Message和Handler类的操作,都会比较不太理解,现在完成一个更新的操作(子线程向主线程发送消息)。
<LinearLayout 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:orientation="vertical"><TextViewandroid:id="@+id/info"android:layout_width="wrap_content"android:layout_height="wrap_content"/>
</LinearLayout>
下面就是希望完成文本自动更新的操作,使用任务管理器完成(TimerTask)。
package com.example.messageproject;import java.util.Timer;
import java.util.TimerTask;import android.app.Activity;
import android.os.Bundle;
import android.os.Handler;
import android.os.Message;
import android.widget.TextView;public class MainActivity extends Activity {private TextView info = null;private static int count = 0;public static final int SET = 1;//定义消息的标记private Handler myHandler = new Handler(){@Overridepublic void handleMessage(Message msg) {switch(msg.what){case SET:MainActivity.this.info.setText("Wanczy-" + count++);break;}}};@Overrideprotected void onCreate(Bundle savedInstanceState) {super.onCreate(savedInstanceState);super.setContentView(R.layout.activity_main);this.info = (TextView) super.findViewById(R.id.info);Timer timer = new Timer();//定义调度器timer.schedule(new MyTimerTask(), 0, 1000);//启动定时调度}/*** 定义了一个子线程* @author Administrator**/private class MyTimerTask extends TimerTask{@Overridepublic void run() {Message msg = new Message();//定义消息msg.what = SET;//定义操作标记MainActivity.this.myHandler.sendMessage(msg);//发送消息}}
}
对于这个程序而言,发现是在Handler中处理组件(TextView)的,为什么不在子线程中完成呢?
01-26 08:24:47.374: ERROR/AndroidRuntime(3533): android.view.ViewRoot$CalledFromWrongThreadException: Only the original thread that created a view hierarchy can touch its views.
这个错误指:子线程不能更新主线程中各个组件的状态。表示只要是子线程就无法去更新组件,那么现在只能采用之前的方法,在子线程中返回要操作的信息,而后主线程中利用Handler处理这些消息,从而实现线程的操作。
在正常的开发之中,不需要开发者去手动处理Looper,Activity类中会自动的启动好。
范例:Looper进行通讯操作:
package com.example.messageproject;import android.app.Activity;
import android.os.Bundle;
import android.os.Handler;
import android.os.Looper;
import android.os.Message;
import android.view.View;
import android.view.View.OnClickListener;
import android.widget.Button;
import android.widget.TextView;public class MainActivity extends Activity {private TextView info = null;private Button but = null;public static final int SET = 1;//定义消息的标记@Overrideprotected void onCreate(Bundle savedInstanceState) {super.onCreate(savedInstanceState);super.setContentView(R.layout.activity_main);this.info = (TextView) super.findViewById(R.id.info);this.but = (Button) super.findViewById(R.id.but);this.but.setOnClickListener(new OnClickListenerImpl());} private class OnClickListenerImpl implements OnClickListener{@Overridepublic void onClick(View v) {Looper looper = Looper.myLooper();//取得Looper对象MyHandler handler = new MyHandler(looper);handler.removeMessages(0);//清空队列中所有消息String data = "厦门万策智业科技有限公司(Wanczy)";Message msg = handler.obtainMessage(SET, data);handler.sendMessage(msg);//发送消息}}private class MyHandler extends Handler{public MyHandler(Looper looper){//用来接收Loopersuper(looper);}@Overridepublic void handleMessage(Message msg) {switch(msg.what){case SET:MainActivity.this.info.setText(msg.obj.toString());//取得消息的内容break;}}}
}
在程序中,去掉Looper之后,发现程序的运行也是一样的,说明Activity程序会自动启动Looper,很多时候不需要开发者去定义Looper。现在我们程序里面这3个关键类都有使用了,对于操作而言,以后就只需要用到Message 和Handler,下面我们来完成一个子线程与主线程的数据交互。
对于子线程,不能更新组件,所以接受到消息之后也只能进行后台的输出。
<LinearLayout 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:orientation="vertical"><TextViewandroid:id="@+id/info"android:layout_width="match_parent"android:layout_height="wrap_content"/><Buttonandroid:id="@+id/but"android:layout_width="match_parent"android:layout_height="wrap_content"android:text="交互"/>
</LinearLayout>
package com.example.messageproject;import android.app.Activity;
import android.os.Bundle;
import android.os.Handler;
import android.os.Looper;
import android.os.Message;
import android.view.View;
import android.view.View.OnClickListener;
import android.widget.Button;
import android.widget.TextView;
public class MainActivity extends Activity {public static final int SETMAIN = 1; // 设置一个what标记public static final int SETCHILD = 2; // 设置一个what标记private Handler mainHandler, childHandler; // 定义Handler对象private TextView msg; // 文本显示组件private Button but; class ChildThread implements Runnable { // 子线程类@Overridepublic void run() {Looper.prepare(); // 初始化LooperMainActivity.this.childHandler = new Handler() {public void handleMessage(Message msg) {switch (msg.what) { // 判断what操作case SETCHILD: // 主线程发送给子线程的信息System.out.println("*** Main Child Message : "+ msg.obj); // 打印消息Message toMain = MainActivity.this.mainHandler.obtainMessage(); // 创建MessagetoMain.obj = "\n\n[B] 这是子线程发给主线程的信息:"; // 设置显示文字toMain.what = SETMAIN; //设置主线程操作的状态码MainActivity.this.mainHandler.sendMessage(toMain); break;}}};Looper.loop(); // 启动该线程的消息队列}}@Overridepublic void onCreate(Bundle savedInstanceState) {super.onCreate(savedInstanceState);super.setContentView(R.layout.activity_main); // 调用布局文件this.msg = (TextView) super.findViewById(R.id.info); // 取得组件this.but = (Button) super.findViewById(R.id.but); // 取得按钮this.mainHandler = new Handler() { // 主线程的Handler对象public void handleMessage(Message msg) { // 消息处理switch (msg.what) { // 判断Message类型case SETMAIN: // 设置主线程的操作类MainActivity.this.msg.setText("主线程接收数据:"+ msg.obj.toString()); // 设置文本内容break;}}};new Thread(new ChildThread(), "Child Thread").start(); // 启动子线程this.but.setOnClickListener(new OnClickListenerImpl()) ; // 单击事件操作}private class OnClickListenerImpl implements OnClickListener {@Overridepublic void onClick(View view) {if (MainActivity.this.childHandler != null) { // 已实例化子线程HandlerMessage childMsg = MainActivity.this.childHandler.obtainMessage(); // 创建一个消息childMsg.obj = MainActivity.this.mainHandler.getLooper().getThread().getName()+ " --> Hello MLDN .";// 设置消息内容childMsg.what = SETCHILD; // 操作码MainActivity.this.childHandler.sendMessage(childMsg); // 向子线程发送}}}@Overrideprotected void onDestroy() {super.onDestroy();MainActivity.this.childHandler.getLooper().quit(); // 结束队列}}
范例:时钟显示
<LinearLayout 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:orientation="vertical"><AnalogClock android:id="@+id/myAnalogClock"android:layout_width="match_parent"android:layout_height="wrap_content"/><TextViewandroid:id="@+id/info"android:layout_width="match_parent"android:layout_height="wrap_content"/>
</LinearLayout>
package com.example.messageproject;import java.text.SimpleDateFormat;
import java.util.Date;import android.app.Activity;
import android.os.Bundle;
import android.os.Handler;
import android.os.Message;
import android.widget.TextView;public class MainActivity extends Activity {private TextView info = null;public static final int SET = 1;private Handler myHandler = new Handler(){@Overridepublic void handleMessage(Message msg) {switch (msg.what){case SET:MainActivity.this.info.setText("当前时间为:"+msg.obj.toString());break;}}};protected void onCreate(Bundle savedInstanceState) {super.onCreate(savedInstanceState);super.setContentView(R.layout.activity_main);this.info = (TextView) super.findViewById(R.id.info);new Thread(new ChildThread()).start();//启动子线程} private class ChildThread implements Runnable{public void run(){while(true){Message msg = MainActivity.this.myHandler.obtainMessage();msg.what = SET;msg.obj = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss").format(new Date());MainActivity.this.myHandler.sendMessage(msg);//发送消息}}}
}
package com.example.messageproject;import java.text.SimpleDateFormat;
import java.util.Date;import android.app.Activity;
import android.os.Bundle;
import android.os.Handler;
import android.os.Message;
import android.widget.TextView;public class MainActivity extends Activity {private TextView info = null;public static final int SET = 1;private Handler myHandler = new Handler(){@Overridepublic void handleMessage(Message msg) {switch (msg.what){case SET:MainActivity.this.info.setText("当前时间为:"+msg.obj.toString());break;}}};protected void onCreate(Bundle savedInstanceState) {super.onCreate(savedInstanceState);super.setContentView(R.layout.activity_main);this.info = (TextView) super.findViewById(R.id.info);new Thread().start();//启动子线程} private class ChildThread implements Runnable{public void run(){while(true){Message msg = MainActivity.this.myHandler.obtainMessage();msg.what = SET;msg.obj = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss").format(new Date());MainActivity.this.myHandler.sendMessage(msg);//发送消息}}}
}
1.3 小结
(1)在Android之中子线程不能直接对主线程的组件进行更新;
相关文章:

Android组件通信——消息机制(二十六)
1. 消息机制 1.1 知识点 (1)掌握Message、Handler、Looper类的使用以及消息的传递; (2)可以通过消息机制动态取得信息; 1.2 具体内容 对于android的消息机制,我们主要要使用Java中线程的一…...

《进化优化》第4章 遗传算法的数学模型
文章目录 4.1 图式理论4.2 马尔可夫链4.3 进化算法的马尔可夫模型的符号4.4 遗传算法的马尔可夫模型4.4.1 选择4.4.2 变异4.4.3 交叉 4.5 遗传算法的动态系统模型4.5.1 选择4.5.2 变异4.5.3 交叉 4.1 图式理论 图式是描述一组个体的位模式,其中用*来表示不在乎的位…...

spring:详解spring MVC
spring MVC SpringMVC是一种基于Java的MVC(Model-View-Controller)Web开发框架,通过将业务逻辑、数据和界面分离,使得开发人员能够更高效地管理和维护代码,提高应用的可扩展性和可维护性。 SpringMVC核心概念 Contr…...

【Leetcode】207.课程表
一、题目 1、题目描述 你这个学期必须选修 numCourses 门课程,记为 0 到 numCourses - 1 。 在选修某些课程之前需要一些先修课程。 先修课程按数组 prerequisites 给出,其中 p r e r e q u i s i t e s [ i ] = [ a i , b...

Ubuntu18.04中QT安装下载安装pcl和vtk以及使用过程中踩过的坑
一、先记录一下下载过程中踩过的坑 问题1:QVTKOpenGLNativeWidget和QVTKWidget 之前从来没有接触过QT中显示3D点云方面的知识,了解到可以用pcl,然后在网上各种找pcl下载的相关内容,想要在QT中显示出来,需要用到VTK&a…...

C++学习——对象数组、成员对象与封闭类
以下内容源于C语言中文网的学习与整理,非原创,如有侵权请告知删除。 一、对象数组 对象数组,即数组的每个元素都是某个类的对象。 1、对象数组中的每个元素都需要用构造函数初始化,具体哪些元素用哪些构造函数初始化,…...

解锁机器学习-梯度下降:从技术到实战的全面指南
目录 一、简介什么是梯度下降?为什么梯度下降重要? 二、梯度下降的数学原理代价函数(Cost Function)梯度(Gradient)更新规则代码示例:基础的梯度下降更新规则 三、批量梯度下降(Batc…...

day62:ARMday9,I2c总线通信
作业:按键中断实现LED1、蜂鸣器、风扇 key_in.c: #include "key_in.h"void gpio_init() {//RCC使能//GPIOERCC->MP_AHB4ENSETR | (0x1<<4);//GPIOBRCC->MP_AHB4ENSETR | (0x1<<1);//PE10、PB6、PE9输出模式GPIOE->MODER & ~(0…...

【Python学习笔记】类型/运算/变量/注释
前言 人生苦短,追求生产力,做一只时代风口的猪,应该学python Python语言中,所有的数据都被称之为对象。 1. 对象类型 Python语言中,常用的数据类型有: 整数, 比如 3 小数(也叫浮…...

国内常用源开发环境换源(flutter换源,python换源,Linux换源,npm换源)
flutter换源 使用环境变量:PUB_HOSTED_URL FLUTTER_STORAGE_BASE_URL, upgrade出问题时可能会提示设置FLUTTER_GIT_URL变量。 flutter中国 PUB_HOSTED_URLhttps://pub.flutter-io.cn FLUTTER_STORAGE_BASE_URLhttps://storage.flutter-io.cn FLUTTER_GIT_URLhtt…...

关于一篇什么是JWT的原理与实际应用
目录 一.介绍 1.1.什么是JWT 二.结构 三.Jwt的工具类的使用 3.1. 依赖 3.2.工具类 3.3.过滤器 3.4.控制器 3.5.配置 3.6. 测试类 用于生成JWT 解析Jwt 复制jwt,并延时30分钟 测试JWT的有效时间 测试过期JWT的解析 四.应用 今天就到这了,希…...

【Method】把 arXiv论文 转换为 HTML5 网页
文章目录 MethodReference https://ar5iv.labs.arxiv.org/ Articles from arXiv.org as responsive HTML5 web pages. 可以将来自 arXiv 的 PDF 论文渲染成 HTML5 网页版本。 Method View any arXiv article URL by changing the X to a 5. 将 arXiv 网址中的 x 换成 5 再回…...

每日一题AC
4.小花和小草正在沙滩上玩挖沙洞的游戏。他们划了一条长度为n米的线作为挖沙洞的参考线路,小花和小草分别从两头开始沿着划好的线开始挖洞,小花每隔a米挖一个洞,小草每隔b米挖一个洞,碰到已经挖过洞的就不需要再挖了。那么&#x…...

后端:推荐 2 个 .NET 操作的 Redis 客户端类库
目录 Redis特点 Redis场景 1. StackExchange.Redis 2. FreeRedis 🚀 快速入门 🎣 Master-Slave (读写分离) 💻 Pipeline (管道)示例 🌌 Redis Cluster (集群) Redis ,是一个高性能(NOSQL)的key-value数据库,Re…...

华泰证券:京东营收增长或短期承压
来源:猛兽财经 作者:猛兽财经 猛兽财经获悉,华泰证券近期发布研报称京东营收增长或短期承压。华泰证券主要观点如下:营收增长或短期承压,聚焦长期内生能力建设 考虑到消费情绪的恢复仍需一定时间,我们预计…...

Java从resources文件下载文档,文档没有后缀名
业务场景:因为公司会对excel文档加密,通过svn或者git上传代码也会对文档进行加密,所以这里将文档后缀去了,这样避免文档加密。 实现思路:将文档去掉后缀,放入resources下,获取输入流࿰…...

【动手学深度学习-Pytorch版】BERT预测系列——BERTModel
本小节主要实现了以下几部分内容: 从一个句子中提取BERT输入序列以及相对的segments段落索引(因为BERT支持输入两个句子)BERT使用的是Transformer的Encoder部分,所以需要需要使用Encoder进行前向传播:输出的特征等于词…...

Python之元组、字典和集合练习
1、餐厅下午茶 (列表与元组 crr66) 某餐厅推出了优惠下午茶套餐活动。顾客可以以优惠的价格从给定的糕点和给定的饮 料中各选一款组成套餐。已知,指定的糕点包括松饼(Muffins)、提拉米苏(Tiramisu)、芝士蛋 糕(Cheese Cake)和三明治(Sandwic…...

【数据结构】归并排序和计数排序(排序的总结)
目录 一,归并排序的递归 二,归并排序的非递归 三,计数排序 四,排序算法的综合分析 一,归并排序的递归 基本思想: 归并采用的是分治思想,是分治法的一个经典的运用。该算法先将原数据进行拆…...

某医疗机构:建立S-SDLC安全开发流程,保障医疗前沿科技应用高质量发展
某医疗机构是头部资本集团旗下专注大健康领域战略性投资与运营的实业公司,市场规模超300亿。该医疗机构已完成数字赋能,形成了标准化、专业化、数字化的疾病和健康管理体系,将进一步规划战略方向,为人工智能纳米技术、高温超导、生…...

验证二叉搜索树的后序遍历序列
LCR 152. 验证二叉搜索树的后序遍历序列 class VerifyTreeOrder:"""LCR 152. 验证二叉搜索树的后序遍历序列https://leetcode.cn/problems/er-cha-sou-suo-shu-de-hou-xu-bian-li-xu-lie-lcof/description/"""def solution(self, postorder: Lis…...

第三章 内存管理 一、内存的基础知识
目录 一、什么是内存 二、有何作用 三、常用数量单位 四、指令的工作原理 五、装入方式 1、绝对装入 2、可重定位装入(静态重定位) 3、动态运行时装入(动态重定位) 六、从写程序到程序运行 七、链接的三种方式 1、静态…...

【Java学习之道】Java常用集合框架
引言 在Java中,集合框架是一个非常重要的概念。它提供了一种方式,让你可以方便地存储和操作数据。Java中的集合框架包括各种集合类和接口,这些类和接口提供了不同的功能和特性。通过学习和掌握Java的集合框架,你可以更好地管理和…...

logicFlow 流程图编辑工具使用及开源地址
一、工具介绍 LogicFlow 是一款流程图编辑框架,提供了一系列流程图交互、编辑所必需的功能和灵活的节点自定义、插件等拓展机制。LogicFlow 支持前端研发自定义开发各种逻辑编排场景,如流程图、ER 图、BPMN 流程等。在工作审批配置、机器人逻辑编排、无…...

ATF(TF-A)/OPTEE之动态代码分析汇总
安全之安全(security)博客目录导读 1、ASAN(AddressSanitizer)地址消毒动态代码分析 2、ATF(TF-A)之UBSAN动态代码分析 3、OPTEE之KASAN地址消毒动态代码分析...

10-11 周三 shell xargs tr curl 做大事情
最近发现,shell的小工具非常的强大,简单记录下 tr命令 -d 删除字符串1中所有输入字符。-s 删除所有重复出现字符序列,只保留第一个;即将重复出现字符串压缩为一个字符串 -d 用于删除查询到的字符串中的空格。 [test3NH-DC-NM1…...

1.1 向量与线性组合
一、向量的基础知识 两个独立的数字 v 1 v_1 v1 和 v 2 v_2 v2,将它们配对可以产生一个二维向量 v \boldsymbol{v} v: 列向量 v v [ v 1 v 2 ] v 1 v 的第一个分量 v 2 v 的第二个分量 \textbf{列向量}\,\boldsymbol v\kern 10pt\boldsymbol …...

django: You may need to add ‘localhost‘ to ALLOWED_HOSTS
参考:https://blog.csdn.net/qq_21744873/article/details/87857279 python manage.py runserver后页面访问失败,提示: DisallowedHost at /admin/ Invalid HTTP_HOST header: ‘localhost:8000’. You may need to add ‘localhost’ to ALLOWED_HOSTS…...

网络安全(黑客技术)—自学手册
1.网络安全是什么 网络安全可以基于攻击和防御视角来分类,我们经常听到的 “红队”、“渗透测试” 等就是研究攻击技术,而“蓝队”、“安全运营”、“安全运维”则研究防御技术。 2.网络安全市场 一、是市场需求量高; 二、则是发展相对成熟…...

【Vue】之Vuex的入门使用,取值,修改值,同异步请求处理---保姆级别教学
一,Vuex入门 1.1 什么是Vuex Vuex是一个专门为Vue.js应用程序开发的状态管理库。它用于管理应用程序中的共享状态,它采用集中式存储管理应用的所有组件的状态,使得状态的管理变得简单和可预测 官方解释:Vuex 是一个专为 Vue.js 应…...