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 ...
随机推荐
- InfluxDB命令使用
身份验证与授权(权限管理) Authentication and Authorization 注意:身份授权与验证不能用于阻止恶意用户.如果有额外的做合理性和安全性的需求,InfluxDB可以运行在第 ...
- Spring实战之环境与profile
1.配置profile bean Spring为环境相关的bean所提供的解决方案其实与构建时的方案没有太大的差别.当然,在这个过程中需要根据环境决定该创建哪个bean和不创建哪个bean.不过Spr ...
- RHCE7 学习里程-3基本命令
一.centos7 基本命令 #创建文件 touch a.b #创建文件夹 mkdir abc #删除文件 rm -f a.b #删除空文件夹 rm -rf abc #重命名文件 mv 源文件 新文 ...
- Spring Boot实践——Filter实现
Filter介绍 Filter是Servlet规范规定的,不属于spring框架,也是用于请求的拦截.但是它适合更粗粒度的拦截,在请求前后做一些编解码处理.日志记录等. 一个Filter包括:1).在 ...
- MySQL group_concat_max_len
MySQL提供的group_concat函数可以拼接某个字段值成字符串,如 select group_concat(user_name) from sys_user,默认的分隔符是 逗号,即" ...
- href 和src 的区别
转载地址:http://www.58maisui.com/2016/08/03/30/?utm_source=tuicool&utm_medium=referral href和src的区别: ...
- #if (DEBUG)
//DEBUG必须大写,其它是不认的#if (DEBUG) Console.WriteLine("Debug");#else Conso ...
- Scala基础:面向对象之trait
trait类似于java中的interface,但是有所不同 Scala中的trait是一种特殊的概念: 首先先将trait作为接口使用,此时的trait就与Java中的接口 (interface)非 ...
- SpringData JPA整理
一 首先熟悉几种jpa中的接口Repository,CrudRepository,PagingAndSortingRepository,JpaRepository,JpaSpecificationEx ...
- dpdk中log的使用方法
1 log简介 dpdk中通过log系统记录相关的日志信息,每一条日志除日志内容外,还有两个附加信息,log级别和log类型.开发人员可根据级别和类型对日志信息进行过滤,只记录必要的日志.1.1 ...