Android-Handler+Message-消息机制
我的理解是,子线程要和主线程通讯,就需要Handler+Message-消息机制

案例一:倒计时Demo(子线程+Handler+Message)
package liudeli.async; import android.os.Handler;
import android.os.Message;
import android.os.SystemClock;
import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;
import android.view.View;
import android.widget.TextView; public class MainActivity extends AppCompatActivity { private TextView tvInfo; @Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main); tvInfo = findViewById(R.id.tv_info);
} /**
* 定义Handler
*/
private Handler mHandler = new Handler(){
@Override
public void handleMessage(Message msg) {
super.handleMessage(msg); if (msg.obj != null) {
tvInfo.setText(msg.obj.toString());
return;
} tvInfo.setText(msg.what + "");
}
}; /**
* 耗时操作不能在主线程 定义主线程
*/
private class MyTimeing implements Runnable { @Override
public void run() {
for (int i = 10; i >= 0; i--) {
// mHandler.obtainMessage(i); 这种消息池方式获取Message消耗小
Message message = mHandler.obtainMessage(i); // what 其实就是ID的意思,唯一标示
if (i <= 0) {
// obj 是Object 什么类型都可以传递: 传递T类型,获取的时候就强转T类型
message.obj = "倒计时完成✅";
}
// 用Android提供的睡眠方法,其实是封装来Thread.sleep
SystemClock.sleep(1000); // 从子线程 发送消息 到---> 主线程的handleMessage方法
mHandler.sendMessage(message);
}
}
} /**
* 执行倒计时
* @param view
*/
public void timeing(View view) {
// 主线程被阻塞 5秒 未响应,系统就会自动报错 ANR Application Not Responding
/**
* Android系统中,ActivityManagerService(简称AMS) 和 WindowManagerService(简称WMS)会检测App的响应时间
* 如果App在特定时间无法响应屏幕触摸或键盘输入事件,或者特定事件没有处理完毕,就会出现ANR
*/
// 启动自行车来做耗时操作
new Thread(new MyTimeing()).start();
}
}
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context=".MainActivity"> <LinearLayout
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:orientation="horizontal"
android:gravity="center"> <TextView
android:id="@+id/tv_info"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="0000000"
android:layout_gravity="center_vertical"
android:textSize="20sp"
android:layout_marginLeft="10dp"
/> <Button
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="倒计时"
android:onClick="timeing"
android:layout_gravity="right"
/> </LinearLayout> </RelativeLayout>

案例二:文字变化(Handler+Message)
package liudeli.async; import android.os.Bundle;
import android.os.Handler;
import android.os.Message;
import android.os.SystemClock;
import android.support.v7.app.AppCompatActivity;
import android.view.View;
import android.widget.TextView; public class MainActivity2 extends AppCompatActivity { private TextView tvInfo; @Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main2); tvInfo = findViewById(R.id.tv_info);
} private int count; /**
* 定义Handler
*/
private Handler mHandler = new Handler(){
@Override
public void handleMessage(Message msg) {
super.handleMessage(msg); if (msg.obj == null) {
return;
}
if (msg.what <= 7) {
tvInfo.setText(msg.obj.toString() + "");
Message message = mHandler.obtainMessage();
message.what = count++;
message.obj = "竟然渐渐清晰 想要说些什么 又不知从何说起" + count;
mHandler.sendMessageDelayed(message, 900);
} }
}; /**
* 执行文字变化
* @param view
*/
public void textChange(View view) {
// mHandler.obtainMessage(i); 这种消息池方式获取Message消耗小
Message message = mHandler.obtainMessage();
message.what = 1;
message.obj = "从那遥远海边 慢慢消失的你 本来模糊的脸";
// 从主线程 发送消息 到---> 主线程的handleMessage方法
mHandler.sendMessageDelayed(message, 800);
count = 0;
}
}
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context=".MainActivity"> <LinearLayout
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:orientation="vertical"
android:gravity="center"> <TextView
android:id="@+id/tv_info"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Test"
android:layout_gravity="center_vertical"
android:textSize="20sp"
android:layout_marginLeft="10dp"
/> <Button
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="文字变化"
android:onClick="textChange"
android:layout_gravity="right"
android:layout_marginTop="20dp"
/> </LinearLayout> </RelativeLayout>

注意:⚠️在Activity的 onDestroy() 方法中,一定要记得回收

postDelayed 看似子线程,其实是属于主线程,postDelayed能延时run,但不能在子线程中执行,否则报错
这个开启的Runnable会在这个Handler所依附线程中运行,而这个Handler是在UI线程中创建的,所以自然地依附在主线程中了。
/**
* 参数一:可以在Runnable中执行UI操作
* 参数二:延时时间 毫秒
* new Handler().postDelayed(Runnable r, long delayMillis);
* @param view
*/
public void test(View view) { new Handler().postDelayed(new Runnable() {
@Override
public void run() {
Toast.makeText(MainActivity2.this, "postDelayed", Toast.LENGTH_LONG).show();
}
}, 2000);
}
子线程 send 到 主线程 的常用方法
// 参数一:Message消息,可传递数据
// 参数二:delayMillis延时时间,延时多久才send,毫秒为单位
// 特点是:send Message消息,并可设置延时时间
// sendMessageDelayed(Message msg, long delayMillis) // 参数一:Message消息,可传递数据
// 特点是:立即send,不延时
// mHandler.sendMessage(Message msg) // 参数一:唯一标识what
// 参数二:delayMillis延时时间,延时多久才send,毫秒为单位
// 特点是:send 唯一标识what,并可设置延时时间
// mHandler.sendEmptyMessageDelayed(int what, long delayMillis) // 参数一:唯一标识what
// 特点是:send 唯一标识what,立即send
// mHandler.sendEmptyMessage(int what)
消息池的概念:
Android操作系统启动后默认会有很多的消息池,这样的方式直接到系统里面消息池拿消息mHandler.obtainMessage(), 而new Message(); 是实例化消息(消耗多些)
推荐用mHandler.obtainMessage()方式
面试题:postDelayed(Runnable r) Runnable 是属于子线程吗?
答:和子线程没有半毛钱关系,命名叫Runnable而已,子线程必须是 有run方法,有.start();
new Thread(){
@Override
public void run() {
super.run();
}
}.start();
按原理来说:子线程是不能执行UI操作,确实不能执行UI操作,但Android设计了API看起来可以在子线程(这是假象),实际是对Handler+Message进行了封装
/**
* 在子线程中操作UI
* @param view
*/
public void uiRun(View view) {
new Thread(){
@Override
public void run() {
super.run();
/**
* 第一种方式
*/
runOnUiThread(new Runnable() {
@Override
public void run() {
Toast.makeText(MainActivity2.this, "runOnUiThread", Toast.LENGTH_LONG).show();
}
}); /**
* 第二种方式
*/
Looper.prepare();
Toast.makeText(MainActivity2.this, "Looper", Toast.LENGTH_LONG).show();
Looper.loop();
}
}.start();
}
Android-Handler+Message-消息机制的更多相关文章
- [Android]Handler的消息机制
最经面试中,技术面试中有一个是Handler的消息机制,细细想想,我经常用到的Handler无非是在主线程(或者说Activity)新建一个Handler对象,另外一个Thread是异步加载数据,同时 ...
- android handler传递消息机制
当工作线程给主线程发送消息时,因为主线程是有looper的,所以不需要初始化looper,注意给谁发消息就关联谁的handler,此时用的就是主线程的handler handler会把消息发送到Mes ...
- 浅析Android中的消息机制(转)
原博客地址:http://blog.csdn.net/liuhe688/article/details/6407225 在分析Android消息机制之前,我们先来看一段代码: public class ...
- 浅析Android中的消息机制(转)
在分析Android消息机制之前,我们先来看一段代码: public class MainActivity extends Activity implements View.OnClickListen ...
- 浅析Android中的消息机制-解决:Only the original thread that created a view hierarchy can touch its views.
在分析Android消息机制之前,我们先来看一段代码: public class MainActivity extends Activity implements View.OnClickListen ...
- 浅析Android中的消息机制
在分析Android消息机制之前,我们先来看一段代码: public class MainActivity extends Activity implements View.OnClickListen ...
- android Handler及消息处理机制的简单介绍
学习android线程时,直接在UI线程中使用子线程来更新TextView显示的内容,会有如下错误:android.view.ViewRoot$CalledFromWrongThreadExcepti ...
- 重温Android中的消息机制
引入: 提到Android中的消息机制,大家应该都不陌生,我们在开发中不可避免的要和它打交道.从我们开发的角度来看,Handler是Android消息机制的上层接口.我们在平时的开发中只需要和Hand ...
- 谈谈对Android中的消息机制的理解
Android中的消息机制主要由Handler.MessageQueue.Looper三个类组成,他们的主要作用是 Handler负责发送.处理Message MessageQueue负责维护Mess ...
- Android中的消息机制
在分析Android消息机制之前.我们先来看一段代码: public class MainActivity extends Activity implements View.OnClickListen ...
随机推荐
- ubuntu 解决“无法获得锁 /var/lib/dpkg/lock -open”的方法
在ubuntu系统终端下,用apt-get install 安装软件的时候,如果在未完成下载的情况下将终端中断,此时 apt-get进程可能没有结束.结果,如果再次运行apt-get instal ...
- vector array and normal stanard array
array 数组的长度固定 vector 自由存储区(栈),动态长度 普通标准数组相对较不安全,不方便; array,vector对象成员函数支持数组越界检测,同时代价是效率问题: array,普通标 ...
- win8下ctrl+alt+down失效问题
最近换win8系统后用myeclipse发现这个用得最多快捷键居然不能用了. 百度后的确是显卡的快捷键冲突,但禁用显卡快捷键后仍然无效,把eclipse换成其他的不能忍. 所以把显卡快捷键换了就可以了 ...
- C# 如何将窗体写到Dll中
步骤: 1.解决方案资源管理器窗口->右击项目属性 2.属性窗口->应用程序->输出类型(U)->类库
- 查看win激活状态的命令
查看win激活状态的命令 1.键盘按下win+R 运行输入如下命令即可. 2.Win+R===>输入 slmgr.vbs -dlv 显示:最为详尽的激活信息,包括:激活ID.安装ID.激活 ...
- ajax传递给后台数组参数方式
出自:http://blog.csdn.net/lingxyd_0/article/details/10428785 在项目上用到了批量删除与批量更改状态,前台使用了EasyUI的DataGrid,用 ...
- ffmpeg源码分析三:transcode_init函数 (转3)
原帖地址:http://blog.csdn.net/austinblog/article/details/25061945 transcode_init()函数是在转换前做准备工作的.下面看看其源代码 ...
- 【POJ1222】EXTENDED LIGHTS OUT
参考博客 https://blog.csdn.net/so_so_y/article/details/76098713 题意 有一些灯泡组成了5*6的方阵.每个开关(开关会使灯泡的状态发生变化)除了控 ...
- Hibernate事务代码规范写法
----------------siwuxie095 事务相关概念 1.什么是事务 逻辑上的一组操作,构成这组操作的各个单元,要么一起成功, 要么一起失败 2.事务的四个特性 1)原子性 2)一致性 ...
- 常见的APP性能测试指标
性能测试在软件的质量保证中起着重要的作用,它包括的测试内容丰富多样.中国软件评测中心将性能测试概括为三个方面:应用在客户端性能的测试.应用在网络上性能的测试和应用在服务器端性能的测试.通常情况下,三方 ...