• Android Handler例程(sendMessage)


    handler的应用场景

    在安卓中,只有主线程才能进行UI操作。说明子线程内无法实现对UI的修改,因此安卓必然支持一种线程通信机制,使得子线程可以发消息让主线程改一下UI,该方案就是handler。

    安卓中子线程之间也需要通信,通信方案也是handler。

    消息机制

    该通信机制分为四个部分:

    message:线程中用来传递的信息载体。

    messagequeue:存放消息的队列。通信机制是异步的,也就是说存放消息与取消息是独立的操作,本质上是一种生产者-消费者模式。

    handler:接收器与发送器的实现。可以理解为是手机,手机可以发消息,也可以收消息。

    looper:消息队列的循环调度器,负责将消息队列里面的消息自动分发给对应的接收器。

    全部代码1

    1. package com.example.handlertest;
    2. import androidx.appcompat.app.AppCompatActivity;
    3. import android.annotation.SuppressLint;
    4. import android.os.Bundle;
    5. import android.os.Handler;
    6. import android.os.Message;
    7. import android.view.View;
    8. import android.widget.Button;
    9. import android.widget.TextView;
    10. public class MainActivity extends AppCompatActivity {
    11. private TextView textView;
    12. private Handler handler;
    13. @Override
    14. protected void onCreate(Bundle savedInstanceState) {
    15. super.onCreate(savedInstanceState);
    16. setContentView(R.layout.activity_main);
    17. TextView textView = findViewById(R.id.text1);
    18. //匿名内部类创建Handler对象
    19. handler = new Handler(){
    20. //重写handleMessage函数对收到的消息进行处理
    21. @Override
    22. public void handleMessage(Message message){
    23. switch (message.what){//根据消息标识进行处理
    24. case 1:
    25. textView.setText("Thread 1!");
    26. break;
    27. case 2:
    28. textView.setText("Thread 2!");
    29. break;
    30. default:
    31. break;
    32. }
    33. }
    34. };
    35. //创建新的子线程1
    36. new Thread(){
    37. @Override
    38. public void run(){
    39. try {
    40. //延时
    41. Thread.sleep(2000);
    42. } catch (InterruptedException e) {
    43. e.printStackTrace();
    44. }
    45. //创建消息对象
    46. Message message = Message.obtain();
    47. //设定消息标识
    48. message.what = 1;
    49. //通过handler将消息发送到消息队列中
    50. handler.sendMessage(message);
    51. }
    52. }.start();//开启线程
    53. //创建新的子线程2
    54. new Thread(){
    55. @Override
    56. public void run(){
    57. try {
    58. //延时,和线程1错开
    59. Thread.sleep(4000);
    60. } catch (InterruptedException e) {
    61. e.printStackTrace();
    62. }
    63. //创建消息对象
    64. Message message = Message.obtain();
    65. //设定消息标识
    66. message.what = 2;
    67. //通过handler将消息发送到消息队列中
    68. handler.sendMessage(message);
    69. }
    70. }.start();//开启线程
    71. }
    72. }

    通过两个线程先后发送消息,改变界面里文字的输出。

    需要注意的是两个线程本身只执行一次,文字改变只有两次。

    代码讲解

    代码中存在三个线程,主线程以及自己设定的两个子线程。

    private Handler handler;

    但是handler对象只需要创建一个,因为进程内部的多个线程是共享内存的,三个线程用的是同一个handler实例。

    本文的代码使用匿名内部类重写handler对象里收到信息后的处理函数handleMessage:

    1. //匿名内部类创建Handler对象
    2. handler = new Handler(){
    3. //重写handleMessage函数对收到的消息进行处理
    4. @Override
    5. public void handleMessage(Message message){
    6. switch (message.what){//根据消息标识进行处理
    7. case 1:
    8. textView.setText("Thread 1!");
    9. break;
    10. case 2:
    11. textView.setText("Thread 2!");
    12. break;
    13. default:
    14. break;
    15. }
    16. }
    17. };

    该实例在主线程中创建,因此处理函数是在主线程进行的,可以进行UI修改。

    也可以不使用匿名内部类,直接定义一种Handler的子类,并在主线程中创建一个对象。在该类的定义中实现对消息处理函数的重写。

    1. //创建消息对象
    2. Message message = Message.obtain();
    3. //设定消息标识
    4. message.what = 1;
    5. //通过handler将消息发送到消息队列中
    6. handler.sendMessage(message);

    在子线程中只需要创建一个消息对象,设置消息内容,并发送到消息队列中即可。

    消息队列messagequeue和循环控制器looper对开发者来说是隐式存在的,程序中仅体现了发送与接收的过程。

    全部代码2

    使用post的方式如下所示:

    1. package com.example.handlertest2;
    2. import androidx.appcompat.app.AppCompatActivity;
    3. import android.os.Bundle;
    4. import android.os.Handler;
    5. import android.widget.TextView;
    6. public class MainActivity extends AppCompatActivity {
    7. public TextView mTextView;
    8. public Handler mHandler;
    9. @Override
    10. protected void onCreate(Bundle savedInstanceState) {
    11. super.onCreate(savedInstanceState);
    12. setContentView(R.layout.activity_main);
    13. mTextView = (TextView) findViewById(R.id.text1);
    14. mHandler = new Handler();
    15. //第一个工作线程
    16. new Thread(){
    17. @Override
    18. public void run(){
    19. try {
    20. Thread.sleep(2000);
    21. } catch (InterruptedException e) {
    22. e.printStackTrace();
    23. }
    24. //传入runnable对象进行发送
    25. mHandler.post(new Runnable() {
    26. @Override
    27. public void run() {
    28. mTextView.setText("Thread 1!");
    29. }
    30. });
    31. }
    32. }.start();
    33. //第二个工作线程
    34. new Thread(){
    35. @Override
    36. public void run(){
    37. try {
    38. Thread.sleep(4000);
    39. } catch (InterruptedException e) {
    40. e.printStackTrace();
    41. }
    42. mHandler.post(new Runnable() {
    43. @Override
    44. public void run() {
    45. mTextView.setText("Thread 2!");
    46. }
    47. });
    48. }
    49. }.start();
    50. }
    51. }

    第二种方法可以不对Handler进行重写,只需要调用其post方法即可。

  • 相关阅读:
    十、Spring Boot 安全管理(5)
    XTuner InternLM-Chat 个人小助手认知微调实践
    QToolButton几个小知识点总结
    Shell之练习一
    阿里二面,前端开发在web3.0中该如何应用,答完面试官对我笑了笑
    Nacos注册中心
    【机器学习9】前馈神经网络
    [数据集][目标检测]螺丝螺母检测数据集VOC+YOLO格式2100张13类别
    你真的会数组去重吗?去重方法汇总解析,看着一篇就够了
    软件与系统安全复习
  • 原文地址:https://blog.csdn.net/m0_37872216/article/details/126348676