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亿。该医疗机构已完成数字赋能,形成了标准化、专业化、数字化的疾病和健康管理体系,将进一步规划战略方向,为人工智能纳米技术、高温超导、生…...
体验Taotoken多模型路由带来的高稳定性与低延迟感受
🚀 告别海外账号与网络限制!稳定直连全球优质大模型,限时半价接入中。 👉 点击领取海量免费额度 体验Taotoken多模型路由带来的高稳定性与低延迟感受 1. 引言:开发中的稳定性与延迟挑战 在将大模型能力集成到应用的过…...
深度学习CNN(一)—— 卷积运算的本质(三十八)
1. 定位导航 🎉 第 9 章 CNN 大门正式开启! CNN 是深度学习历史上最具影响力的架构创新之一: 2012 AlexNet:ImageNet 革命,开启深度学习时代 2015 ResNet:突破"深度极限" 2020 Vision Transformer:CNN 的最大竞争对手出现 直到 2024 年:CNN 仍是图像处理、…...
409.最长回文串(数学算法)
题目 给定一个包含大写字母和小写字母的字符串 s ,返回 通过这些字母构造成的 最长的 回文串 的长度。 在构造过程中,请注意 区分大小写 。比如 "Aa" 不能当做一个回文字符串。 题目链接如下: https://leetcode.cn/problems/longe…...
突发!Gemini Ultra最新v1.5更新导致批量推理吞吐下降38%?我们48小时内完成全链路压测并定位CUDA内核缺陷
更多请点击: https://codechina.net 第一章:Gemini Ultra性能测试的背景与挑战 随着多模态大模型能力边界持续拓展,Gemini Ultra作为Google最新发布的旗舰级AI模型,在推理深度、上下文理解与跨模态协同方面提出了前所未有的工程验…...
XXMI-Launcher:多游戏Mod管理平台的终极指南
XXMI-Launcher:多游戏Mod管理平台的终极指南 【免费下载链接】XXMI-Launcher Modding platform for GI, HSR, WW and ZZZ 项目地址: https://gitcode.com/gh_mirrors/xx/XXMI-Launcher XXMI-Launcher是一款专为热门游戏设计的Mod管理平台,支持《原…...
PIC16F驱动WS2812:8位MCU实现无限随机动态灯光算法
1. 项目概述与核心思路 几年前,我在捣鼓一个节日南瓜灯项目时,遇到了一个经典难题:手头只有一片资源极其有限的PIC16F1847微控制器,却想驱动一串WS2812(也就是大家常说的NeoPixel)LED,做出那种看…...
英雄联盟录像编辑完整教程:5分钟掌握League Director专业工具
英雄联盟录像编辑完整教程:5分钟掌握League Director专业工具 【免费下载链接】leaguedirector League Director is a tool for staging and recording videos from League of Legends replays 项目地址: https://gitcode.com/gh_mirrors/le/leaguedirector …...
Hi3516DV300鸿蒙时钟应用开发:从环境搭建到驱动调试全流程
1. 项目概述:从零到一,在Hi3516DV300上跑通一个鸿蒙时钟最近在捣鼓OpenHarmony,手头正好有一块海思的Hi3516DV300开发板。这块板子性能不错,带屏显,很适合做点有意思的应用。我琢磨着,与其跑个现成的Demo&a…...
GitLab SSH Key配置全流程复盘:从生成、复制到验证,一个命令解决‘Permission denied’
GitLab SSH Key配置全流程:从零开始到高效验证的完整指南 当你第一次在终端看到Permission denied (publickey)这个刺眼的红色错误时,那种挫败感我太熟悉了。三年前我刚接触GitLab时,花了整整一个下午才搞明白SSH Key配置的完整逻辑。本文将带…...
OctoBase源码解析:深入理解Rust实现的本地优先数据库引擎 [特殊字符]
OctoBase源码解析:深入理解Rust实现的本地优先数据库引擎 🐙 【免费下载链接】OctoBase 🐙 OctoBase is the open-source database behind AFFiNE, local-first, yet collaborative. A light-weight, scalable, data engine written in Rust.…...
