我的理解是,子线程要和主线程通讯,就需要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-消息机制的更多相关文章

  1. [Android]Handler的消息机制

    最经面试中,技术面试中有一个是Handler的消息机制,细细想想,我经常用到的Handler无非是在主线程(或者说Activity)新建一个Handler对象,另外一个Thread是异步加载数据,同时 ...

  2. android handler传递消息机制

    当工作线程给主线程发送消息时,因为主线程是有looper的,所以不需要初始化looper,注意给谁发消息就关联谁的handler,此时用的就是主线程的handler handler会把消息发送到Mes ...

  3. 浅析Android中的消息机制(转)

    原博客地址:http://blog.csdn.net/liuhe688/article/details/6407225 在分析Android消息机制之前,我们先来看一段代码: public class ...

  4. 浅析Android中的消息机制(转)

    在分析Android消息机制之前,我们先来看一段代码: public class MainActivity extends Activity implements View.OnClickListen ...

  5. 浅析Android中的消息机制-解决:Only the original thread that created a view hierarchy can touch its views.

    在分析Android消息机制之前,我们先来看一段代码: public class MainActivity extends Activity implements View.OnClickListen ...

  6. 浅析Android中的消息机制

    在分析Android消息机制之前,我们先来看一段代码: public class MainActivity extends Activity implements View.OnClickListen ...

  7. android Handler及消息处理机制的简单介绍

    学习android线程时,直接在UI线程中使用子线程来更新TextView显示的内容,会有如下错误:android.view.ViewRoot$CalledFromWrongThreadExcepti ...

  8. 重温Android中的消息机制

    引入: 提到Android中的消息机制,大家应该都不陌生,我们在开发中不可避免的要和它打交道.从我们开发的角度来看,Handler是Android消息机制的上层接口.我们在平时的开发中只需要和Hand ...

  9. 谈谈对Android中的消息机制的理解

    Android中的消息机制主要由Handler.MessageQueue.Looper三个类组成,他们的主要作用是 Handler负责发送.处理Message MessageQueue负责维护Mess ...

  10. Android中的消息机制

    在分析Android消息机制之前.我们先来看一段代码: public class MainActivity extends Activity implements View.OnClickListen ...

随机推荐

  1. InfluxDB命令使用

    身份验证与授权(权限管理) Authentication and Authorization 注意:身份授权与验证不能用于阻止恶意用户.如果有额外的做合理性和安全性的需求,InfluxDB可以运行在第 ...

  2. Spring实战之环境与profile

    1.配置profile bean Spring为环境相关的bean所提供的解决方案其实与构建时的方案没有太大的差别.当然,在这个过程中需要根据环境决定该创建哪个bean和不创建哪个bean.不过Spr ...

  3. RHCE7 学习里程-3基本命令

    一.centos7  基本命令 #创建文件 touch a.b #创建文件夹 mkdir abc #删除文件 rm -f a.b #删除空文件夹 rm -rf abc #重命名文件 mv 源文件 新文 ...

  4. Spring Boot实践——Filter实现

    Filter介绍 Filter是Servlet规范规定的,不属于spring框架,也是用于请求的拦截.但是它适合更粗粒度的拦截,在请求前后做一些编解码处理.日志记录等. 一个Filter包括:1).在 ...

  5. MySQL group_concat_max_len

    MySQL提供的group_concat函数可以拼接某个字段值成字符串,如 select group_concat(user_name) from sys_user,默认的分隔符是 逗号,即" ...

  6. href 和src 的区别

    转载地址:http://www.58maisui.com/2016/08/03/30/?utm_source=tuicool&utm_medium=referral href和src的区别: ...

  7. #if (DEBUG)

    //DEBUG必须大写,其它是不认的#if (DEBUG)            Console.WriteLine("Debug");#else            Conso ...

  8. Scala基础:面向对象之trait

    trait类似于java中的interface,但是有所不同 Scala中的trait是一种特殊的概念: 首先先将trait作为接口使用,此时的trait就与Java中的接口 (interface)非 ...

  9. SpringData JPA整理

    一 首先熟悉几种jpa中的接口Repository,CrudRepository,PagingAndSortingRepository,JpaRepository,JpaSpecificationEx ...

  10. dpdk中log的使用方法

    1 log简介    dpdk中通过log系统记录相关的日志信息,每一条日志除日志内容外,还有两个附加信息,log级别和log类型.开发人员可根据级别和类型对日志信息进行过滤,只记录必要的日志.1.1 ...