草庐IT

Android的handler消息收发处理——子线程与主线程(UI线程)间的通信

昊月光华 2023-05-02 原文

 

目录

写在前面 

基础概念

什么是handler?

什么是looper?

什么是消息队列(MessageQueue)?

在子线程中使用子线程中的数据更新UI线程

主线程与子线程通信实例(程序代码)

 子线程获取主线程handler发送数据给主线程。

 主线程发信息给子线程


写在前面 

时间截止到2022年9月2日。(为什么说明时间,因为安卓在不断地更新不断地完善,今天能跑的代码放到明天不一定能正常运行,因为安卓完善可能会因为性能原因舍弃掉某些功能的实现或者是以新的算法来优化原来的功能)

基础概念

在其他线程中更新UI界面被安卓认为是不安全的,安卓是不允许的,UI线程(主线程)当然可以更新UI界面,于是可以通过其他线程发数据(通信内容)给UI线程让其帮忙更新数据。

什么是handler?

handler主要接受子进程的发送的数据,并用此数据配合主线程更新UI.

以我个人使用而言,见字面意思,它是一个消息处理类。使用必须重写其中的handleMessage(Message  msg)方法,一个线程如果获得了另一个线程的handler对象,则能通过另一个线程的handler.sendxxx发送信息。

Message msg 的常用属性有 

.obj (Object类型)   可以是任意类型的数据,取出来后再强制转换即可。

 .what(int类型)我个人使用用于判断由那个控件产生的事件引起的通信。

目前handler的空参构造已经被废弃,可以通过指定的looper来进行构造。

#例如在主线程中构造handler

  private Handler mHandler= new Handler(Looper.getMainLooper()) {
        @Override
        //重写handleMessage方法,根据msg中what的值判断是否执行后续操作
        public void handleMessage(Message msg) {

            if (msg.what == 0) {
                i++;
                runt.setText(String.valueOf(i));
            }
        }
    };

什么是looper?

        正如上面的handler可以发送消息,Message(消息)由一个消息队列进行管理,而消息队列又是由一个looper进行管理的,Looper负责管理线程的消息队列和消息循环,在主线程中自动创建了一个looper,而其他子线程则需要自己手动创建。

        在主线程中,通过Loop.getMainLooper可以获得主进程的Looper对象。

        在子进程中,先Looper.prepare()创建消息队列,再通过Loop.myLooper得到当前线程的Looper对象,最后通过Looper.loop进入消息循环。

   

总结:     

 handler与looper是唯一映射的关系;

一个handler只能拥有一个looper;

一个looper只能和一个线程相照应,同时一个looper也对应着唯一一个MessageQueue。  
 一个looper却可以拥有多个handler (因为handler可以通过指定looper来创建)

 

比如在子线程中创建handler

  class Ctrl extends Thread {
            public  Handler Chandler;
            public  Looper Clooper =Looper.myLooper();

            public  void    run(){

                Looper.prepare();
                Chandler=new Handler(Clooper){
                    @Override
                    public void handleMessage(Message msg) {
                        if(msg.what== 0){

                            Log.e(TAG, "子线程收到消息" );

                    }
                    }

                };

                Looper.loop();

            }




    }


 

什么是消息队列(MessageQueue)?

它是由Looper这个管理类所维护的,handler分发一个消息,消息队列中的消息加1,Looper.loop不断从队头取出消息供handler处理。

在子线程中使用子线程中的数据更新UI线程

使用方法

 MainActivity.this.runOnUiThread(new Runnable() // 重写其中run方法

比如

         MainActivity.this.runOnUiThread(new Runnable() {
                    @Override
                    public void run() {
                        runt.setText(time+"s");
                        tl.setText(TempLimit);
                        hl.setText(HumiLimit);
                        ll.setText(LsLimit);
                        isc.setText(_isc);

                        temp.setText(_temp);
                        humi.setText(_humi);
                        ls.setText(_ls);



                        if(cons)state.setText("已连接");
                        else {
                            state.setText("断开连接");
                            state.setTextColor(R.color.red);
                        }
                    }
                });

主线程与子线程通信实例(程序代码)

 子线程获取主线程handler发送数据给主线程。

在UI中的oncreate中

  mhandler=new Handler(Looper.getMainLooper()){
            @Override
            public void handleMessage(Message msg) {
                if(msg.what==0){
                    Log.e(TAG, "主线程收到消息:"+(String) msg.obj );
                }
            }
        };

在子线程中

 class Ctrl extends Thread {

        Message msg;
        public  void  run(){
            while (true){
                try {
                    Thread.sleep(1000);
                    msg=new Message();
                    msg.what=0;
                    msg.obj="hello";
                    mhandler.sendMessage(msg);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
        }

           





    }
}

 效果:

 主线程发信息给子线程

值得注意的是,子线程的handler需要在子线程中创建looper,通过

Looper.prepare();

创建。

 具体代码

package com.example.yuezhenhao;

import androidx.appcompat.app.AppCompatActivity;

import android.annotation.SuppressLint;
import android.os.Bundle;
import android.os.Handler;
import android.os.Looper;
import android.os.Message;
import android.util.Log;
import android.view.View;
import android.widget.ImageView;
import android.widget.TextView;

import java.util.Timer;
import java.util.TimerTask;

import javax.security.auth.Subject;

//
public class UIshow extends AppCompatActivity {

    private  String TAG="UIshow";
  

    private  Handler subandler;  //子线程handler对象
   
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_uishow);
      




        Ctrl  ctrlthread=new Ctrl();
        ctrlthread.start();





        new Timer().schedule(new TimerTask() {
            @SuppressLint("ResourceAsColor")
            @Override
            public void run() {
                if(subandler != null) subandler.sendEmptyMessage(0);
            }},0,1000);





    }


///子线程

    class Ctrl extends Thread {


          public  Handler Chandler;




            public  void    run(){

                Looper.prepare();
                Chandler=new Handler(Looper.myLooper()){
                    @Override
                    public void handleMessage(Message msg) {
                        if(msg.what== 0){

                            Log.e(TAG, "子线程收到消息" );

                    }
                    }

                };
                if(subandler == null) {
                    subandler= Chandler;
                }
                Looper.loop();

            }






    }


}

效果: 

 

有关Android的handler消息收发处理——子线程与主线程(UI线程)间的通信的更多相关文章

  1. ruby - i18n Assets 管理/翻译 UI - 2

    我正在使用i18n从头开始​​构建一个多语言网络应用程序,虽然我自己可以处理一大堆yml文件,但我说的语言(非常)有限,最终我想寻求外部帮助帮助。我想知道这里是否有人在使用UI插件/gem(与django上的django-rosetta不同)来处理多个翻译器,其中一些翻译器不愿意或无法处理存储库中的100多个文件,处理语言数据。谢谢&问候,安德拉斯(如果您已经在ruby​​onrails-talk上遇到了这个问题,我们深表歉意) 最佳答案 有一个rails3branchofthetolkgem在github上。您可以通过在Gemfi

  2. ruby - 如何指定 Rack 处理程序 - 2

    Rackup通过Rack的默认处理程序成功运行任何Rack应用程序。例如:classRackAppdefcall(environment)['200',{'Content-Type'=>'text/html'},["Helloworld"]]endendrunRackApp.new但是当最后一行更改为使用Rack的内置CGI处理程序时,rackup给出“NoMethodErrorat/undefinedmethod`call'fornil:NilClass”:Rack::Handler::CGI.runRackApp.newRack的其他内置处理程序也提出了同样的反对意见。例如Rack

  3. ruby-on-rails - Rails 应用程序之间的通信 - 2

    我构建了两个需要相互通信和发送文件的Rails应用程序。例如,一个Rails应用程序会发送请求以查看其他应用程序数据库中的表。然后另一个应用程序将呈现该表的json并将其发回。我还希望一个应用程序将存储在其公共(public)目录中的文本文件发送到另一个应用程序的公共(public)目录。我从来没有做过这样的事情,所以我什至不知道从哪里开始。任何帮助,将不胜感激。谢谢! 最佳答案 无论Rails是什么,几乎所有Web应用程序都有您的要求,大多数现代Web应用程序都需要相互通信。但是有一个小小的理解需要你坚持下去,网站不应直接访问彼此

  4. ruby - RuntimeError(自动加载常量 Apps 多线程时检测到循环依赖 - 2

    我收到这个错误:RuntimeError(自动加载常量Apps时检测到循环依赖当我使用多线程时。下面是我的代码。为什么会这样?我尝试多线程的原因是因为我正在编写一个HTML抓取应用程序。对Nokogiri::HTML(open())的调用是一个同步阻塞调用,需要1秒才能返回,我有100,000多个页面要访问,所以我试图运行多个线程来解决这个问题。有更好的方法吗?classToolsController0)app.website=array.join(',')putsapp.websiteelseapp.website="NONE"endapp.saveapps=Apps.order("

  5. ruby-on-rails - 如何在 Rails View 上显示错误消息? - 2

    我是rails的新手,想在form字段上应用验证。myviewsnew.html.erb.....模拟.rbclassSimulation{:in=>1..25,:message=>'Therowmustbebetween1and25'}end模拟Controller.rbclassSimulationsController我想检查模型类中row字段的整数范围,如果不在范围内则返回错误信息。我可以检查上面代码的范围,但无法返回错误消息提前致谢 最佳答案 关键是您使用的是模型表单,一种显示ActiveRecord模型实例属性的表单。c

  6. ruby-on-rails - 如何在 Ruby on Rails 中实现由 JSF 2.0 (Primefaces) 驱动的 UI 魔法 - 2

    按照目前的情况,这个问题不适合我们的问答形式。我们希望答案得到事实、引用或专业知识的支持,但这个问题可能会引发辩论、争论、投票或扩展讨论。如果您觉得这个问题可以改进并可能重新打开,visitthehelpcenter指导。关闭10年前。问题1)我想知道ruby​​onrails是否有功能类似于primefaces的gem。我问的原因是如果您使用primefaces(http://www.primefaces.org/showcase-labs/ui/home.jsf),开发人员无需担心javascript或jquery的东西。据我所知,JSF是一个规范,基于规范的各种可用实现,prim

  7. ruby - 使用 Ruby 通过 Outlook 发送消息的最简单方法是什么? - 2

    我的工作要求我为某些测试自动生成电子邮件。我一直在四处寻找,但未能找到可以快速实现的合理解决方案。它需要在outlook而不是其他邮件服务器中,因为我们有一些奇怪的身份验证规则,我们需要保存草稿而不是仅仅发送邮件的选项。显然win32ole可以做到这一点,但我找不到任何相当简单的例子。 最佳答案 假设存储了Outlook凭据并且您设置为自动登录到Outlook,WIN32OLE可以很好地完成此操作:require'win32ole'outlook=WIN32OLE.new('Outlook.Application')message=

  8. Ruby - 如何将消息长度表示为 2 个二进制字节 - 2

    我正在使用Ruby,我正在与一个网络端点通信,该端点在发送消息本身之前需要格式化“header”。header中的第一个字段必须是消息长度,它被定义为网络字节顺序中的2二进制字节消息长度。比如我的消息长度是1024。如何将1024表示为二进制双字节? 最佳答案 Ruby(以及Perl和Python等)中字节整理的标准工具是pack和unpack。ruby的packisinArray.您的长度应该是两个字节长,并且按网络字节顺序排列,这听起来像是n格式说明符的工作:n|Integer|16-bitunsigned,network(bi

  9. MIMO-OFDM无线通信技术及MATLAB实现(1)无线信道:传播和衰落 - 2

     MIMO技术的优缺点优点通过下面三个增益来总体概括:阵列增益。阵列增益是指由于接收机通过对接收信号的相干合并而活得的平均SNR的提高。在发射机不知道信道信息的情况下,MIMO系统可以获得的阵列增益与接收天线数成正比复用增益。在采用空间复用方案的MIMO系统中,可以获得复用增益,即信道容量成倍增加。信道容量的增加与min(Nt,Nr)成正比分集增益。在采用空间分集方案的MIMO系统中,可以获得分集增益,即可靠性性能的改善。分集增益用独立衰落支路数来描述,即分集指数。在使用了空时编码的MIMO系统中,由于接收天线或发射天线之间的间距较远,可认为它们各自的大尺度衰落是相互独立的,因此分布式MIMO

  10. ruby-on-rails - 在 Flash 警报 Rails 3 中显示错误消息 - 2

    如果我在模型中设置验证消息validates:name,:presence=>{:message=>'Thenamecantbeblank.'}我如何让该消息显示在闪光警报中,这是我迄今为止尝试过的方法defcreate@message=Message.new(params[:message])if@message.valid?ContactMailer.send_mail(@message).deliverredirect_to(root_path,:notice=>"Thanksforyourmessage,Iwillbeintouchsoon")elseflash[:error]

随机推荐