我的理解是,子线程要和主线程通讯,就需要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. Tkinter LabelFrame

       Tkinter LabelFrame: 在一个labelframe一个简单的容器构件.其主要目的是作为一个间隔或复杂的窗口布局容器. 在一个labelframe一个简单的容器构件.其主要目的是作 ...

  2. 版本控制git之一 - 仓库管理

    git 再开始这个话题之前,让我想起了一件很痛苦的事情,在我大学写毕业论文的时候,我当时的文件是这样保存的 毕业论文_初稿.doc 毕业论文_修改1.doc 毕业论文_修改2.doc 毕业论文_修改3 ...

  3. 使用Tor创建.onion域名网站(创建暗网服务和暗网的网站)

    使用Tor 的.onion域名创建匿名服务器 Tor不仅可以提供客户端的匿名访问,Tor还可以提供服务器的匿名.通过使用Tor网络,用户可以维护位置不可知的服务器.当然如果要访问这个隐蔽的服务,客户端 ...

  4. mfc对话框启动就直接隐藏在右下角显示托盘图标

    之前在网络上找了一份mfc对话框启动就直接隐藏窗体,在右下角显示托盘图标的demo 在win7下可以正常使用,但在win10上直接溢出,导致计算机跟注销似的崩溃现象. 后来找到原因是因为在OnInit ...

  5. JAVA压缩 解压缩zip 并解决linux下中文乱码

    1. [代码][Java]代码   1:再压缩前,要设置linux模式, 需要使用第三方ant-1.6.5.jar  如果是文件目录,则ZipEntry zipEntry=new ZipEntry(b ...

  6. Halcon标定

    摄像头拍摄时候,图像均有畸变,但是图像的扭曲变形均是有规律的成线性的,所以可以通过算法矫正.halcon标定过程需要在镜头内放置标定板:标定板一般选用30*30mm的:可以通过halcon程序来制作: ...

  7. Python常见字符串处理操作

    Python中字符串处理的方法已经超过37种了,下面是一些常用的字符串处理的方法,以后慢慢添加. >>> s = 'Django is cool' #创建一个字符串 >> ...

  8. 用Pylint规范化Python代码,附PyCharm配置

    Pylint一个可以检查Python代码错误,执行代码规范的工具.它还可以对代码风格提出建议. 官网:https://pylint.readthedocs.io pip install pylint ...

  9. java 蓝桥杯算法提高 矩阵乘法

    思路:根据提示的内容,我们可以得到c[i][j] += a[i][k]*b[k][j],k>=0&&k<s PS:这道题本身不难,但是当我定义A[m][s] B[s][n] ...

  10. solr的客户端操作:使用solrj进行curd操作

    导入相关的jar包 <dependency> <groupId>org.apache.solr</groupId> <artifactId>solr-s ...