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亿。该医疗机构已完成数字赋能,形成了标准化、专业化、数字化的疾病和健康管理体系,将进一步规划战略方向,为人工智能纳米技术、高温超导、生…...
【杂谈】-递归进化:人工智能的自我改进与监管挑战
递归进化:人工智能的自我改进与监管挑战 文章目录 递归进化:人工智能的自我改进与监管挑战1、自我改进型人工智能的崛起2、人工智能如何挑战人类监管?3、确保人工智能受控的策略4、人类在人工智能发展中的角色5、平衡自主性与控制力6、总结与…...
Flask RESTful 示例
目录 1. 环境准备2. 安装依赖3. 修改main.py4. 运行应用5. API使用示例获取所有任务获取单个任务创建新任务更新任务删除任务 中文乱码问题: 下面创建一个简单的Flask RESTful API示例。首先,我们需要创建环境,安装必要的依赖,然后…...
Leetcode 3576. Transform Array to All Equal Elements
Leetcode 3576. Transform Array to All Equal Elements 1. 解题思路2. 代码实现 题目链接:3576. Transform Array to All Equal Elements 1. 解题思路 这一题思路上就是分别考察一下是否能将其转化为全1或者全-1数组即可。 至于每一种情况是否可以达到…...
.Net框架,除了EF还有很多很多......
文章目录 1. 引言2. Dapper2.1 概述与设计原理2.2 核心功能与代码示例基本查询多映射查询存储过程调用 2.3 性能优化原理2.4 适用场景 3. NHibernate3.1 概述与架构设计3.2 映射配置示例Fluent映射XML映射 3.3 查询示例HQL查询Criteria APILINQ提供程序 3.4 高级特性3.5 适用场…...
为什么需要建设工程项目管理?工程项目管理有哪些亮点功能?
在建筑行业,项目管理的重要性不言而喻。随着工程规模的扩大、技术复杂度的提升,传统的管理模式已经难以满足现代工程的需求。过去,许多企业依赖手工记录、口头沟通和分散的信息管理,导致效率低下、成本失控、风险频发。例如&#…...
JDK 17 新特性
#JDK 17 新特性 /**************** 文本块 *****************/ python/scala中早就支持,不稀奇 String json “”" { “name”: “Java”, “version”: 17 } “”"; /**************** Switch 语句 -> 表达式 *****************/ 挺好的ÿ…...
华为云Flexus+DeepSeek征文|DeepSeek-V3/R1 商用服务开通全流程与本地部署搭建
华为云FlexusDeepSeek征文|DeepSeek-V3/R1 商用服务开通全流程与本地部署搭建 前言 如今大模型其性能出色,华为云 ModelArts Studio_MaaS大模型即服务平台华为云内置了大模型,能助力我们轻松驾驭 DeepSeek-V3/R1,本文中将分享如何…...
dify打造数据可视化图表
一、概述 在日常工作和学习中,我们经常需要和数据打交道。无论是分析报告、项目展示,还是简单的数据洞察,一个清晰直观的图表,往往能胜过千言万语。 一款能让数据可视化变得超级简单的 MCP Server,由蚂蚁集团 AntV 团队…...
C#中的CLR属性、依赖属性与附加属性
CLR属性的主要特征 封装性: 隐藏字段的实现细节 提供对字段的受控访问 访问控制: 可单独设置get/set访问器的可见性 可创建只读或只写属性 计算属性: 可以在getter中执行计算逻辑 不需要直接对应一个字段 验证逻辑: 可以…...
使用LangGraph和LangSmith构建多智能体人工智能系统
现在,通过组合几个较小的子智能体来创建一个强大的人工智能智能体正成为一种趋势。但这也带来了一些挑战,比如减少幻觉、管理对话流程、在测试期间留意智能体的工作方式、允许人工介入以及评估其性能。你需要进行大量的反复试验。 在这篇博客〔原作者&a…...
