我的理解是,子线程要和主线程通讯,就需要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. C经典实例

    1,九九乘法表 undefined reference to `sqrt' linux本身无math库 -lm,伪链接;

  2. Zedgraph悬停时显示内容闪烁的解决

    中修改 HandleCursorValues 如下形式即可. // weng modified on 20170531 1016 private Point lastMovedPoint; priva ...

  3. centOS安装openoffice的方法

    centOS安装openoffice的方法 分类: centOS 2012-06-15 10:24 2872人阅读 评论(0) 收藏 举报 centos测试 yum install openoffic ...

  4. Android MVP模式简单易懂的介绍方式 (二)

    Android MVP模式简单易懂的介绍方式 (一) Android MVP模式简单易懂的介绍方式 (二) Android MVP模式简单易懂的介绍方式 (三) 上一篇文章我们介绍完了Model的创建 ...

  5. C++Primer笔记-----day02

    ====================================================================day02=========================== ...

  6. nexus3 搭建maven远程仓库

    右上角 下载maven http://maven.apache.org/download.cgi 下载nexus https://www.sonatype.com/download-oss-sonat ...

  7. 简析SynchronousQueue,LinkedBlockingQueue,ArrayBlockingQueue

    SynchronousQueue SynchronousQueue是无界的,是一种无缓冲的等待队列,但是由于该Queue本身的特性,在某次添加元素后必须等待其他线程取走后才能继续添加:可以认为Sync ...

  8. RouterOS DNS劫持(转)

    什么是DNS劫持 DNS劫持就是通过技术手段,来控制用户解析域名的IP地址.举个例子,正常解析域名www.awolf.net时应该返回IP:64.64.30.60:但现在通过DNS劫持,使域名www. ...

  9. 【原】Coursera—Andrew Ng机器学习—编程作业 Programming Exercise 4—反向传播神经网络

    课程笔记 Coursera—Andrew Ng机器学习—课程笔记 Lecture 9_Neural Networks learning 作业说明 Exercise 4,Week 5,实现反向传播 ba ...

  10. boxing & unboxing

    [boxing & unboxing] Boxing is the process of converting a value type to the type object or to an ...