Handler,Looper,MessageQueue三剑客的合作方式

本文深入解析Android中的消息机制,详细介绍了Handler、MessageQueue与Looper三者的功能与协作方式。通过实例演示了如何在自定义线程中使用这些组件实现UI更新。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

三剑客各自的绝招

Handler在消息传递机制里扮演着很重要的角色,它是用来发送消息与处理消息的。
MessageQueue则是用来存储Message信息的队列,它采用的是先进先出的方式。
Looper则用来负责读取MessageQueue中的Message消息的,在读到消息后再将消息改善给该消息的Handler进行处理。

三剑客的关系及合作的方式

首先我们来看看Looper的构造器代码
private Looper
{
    mQueue = new MessageQueue();
    mRun = true;
    mThread = Thread.currentThread();
}
从上面我们可以看到当我们新建初始化一个Looper的时候,默认就会帮我们加上一个与之对应的MessageQueue,想想也是,如果没有对应的消息队列,那么Looper还怎么读取得到信息呢?
再进一步,Handler是用来发送消息的,那么消息一旦发送出去,就像信封发出去的时候,你需要一个信箱吧,那么android里面的消息传递机制里面信箱的角色是由谁来扮演的呢?这个MessageQueue就当仁不让地承担下这个重任了。
既然Handler离不开MessageQueue,而MessageQueue又是由Looper生成,那么可以说Handler也就跟Looper有着难舍难分的关系了。由此可以看出,它们三者合而生,分则完。只有三者三剑合璧,才能将消息传递的任务给做好。
或者有人会问,那么为什么有时在主线程里面看不到Looper与MessageQueue的身影呢,只要定义Handler也可以发送消息与处理消息?其实这个是因为主线程里面已经提前给我们定义了一个Looper对象,也就有了相应的MessageQueue。这样,我们当然可以只定义Handler这一个了。但如果我们要想让自己定义的线程也加入到整个消息传递里面来,毫无疑问,我们需要自己一个Looper对象,才能正常地发送并处理消息。

接下来就让我们来看看一个自定义的线程的处理的信息。

//定义一个自定义的需要改变UI界面的线程,
    class MyThread extends Thread{
        public Handler mHandler;
        public void run(){
            //调用looper的prepare()可以进行Looper的初始化
            Looper.prepare();
            mHandler = new Handler(){
                //定义处理消息的方法
                @Override
                public void handleMessage(Message msg){
                    if(msg.what == 0x123){
                        //在此处可以定义自己要执行的代码,一般为请求网络数据或者计算量大的计算
                        Message mainMessage = new Message();
                        //都可以将message的what赋值为0x123,并不会互相干扰,因为它们隶属不同的messageQueue,因为它们由不同的handler发送。handler发送消息到指定的message里面。这里是将参数发回主线程去修改UI界面
                        mainMessage.what = 0x123;
                        Bundle mainBundle = new Bundle();
                        //可以在message里面放许多的数据,比如ArrayList,借用bundle
                        mainBundle.putIntegerArrayList("nums",(ArrayList)nums);
                        mainMessage.setData(mainBundle);
                        MainActivity.this.mainHandler.sendMessage(mainMessage);
                    }
                }
            };
            //Looper.loop()执行后,Looper开始不断循环从MessageQueue读取消息。
            Looper.loop();
        }
    }
myThread = new MyThread();
        //启动新线程,当线程启动后,线程里面的消息循环也就开始运行,并时刻接受来自于myThread.handler发送来的消息。
        listPrimeThread.start();
Message msg = new Message();
        msg.what = 0x123;
        Bundle bundle = new Bundle();
        bundle.putInt(UPPER_NUM,
                Integer.parseInt(et.getText().toString()));
        msg.setData(bundle);
        //向自定义的线程中的Handler发送消息
        myThread.mHandler.sendMessage(msg);
我们需要定义一个Handler来接受来自自定义线程发来的修改UI界面的消息。必须清楚的是主线程与自定义线程是不同的线程,它们各自拥有一套消息传递机制。
Handler mainHandler = new Handler(){
        public void handleMessage(Message msg){
        //msg.what赋值为一样的值不会有所干扰。
            if(msg.what == 0x123){
                et = (EditText) findViewById(R.id.et);
                ArrayList<Integer>nums = msg.getData().getIntegerArrayList("nums");
                et.setText(nums.toString());
            }
        }
    };

顺便提一提,如果我们直接在刚才自定义的myThread里面通过下面语句修改UI界面,虽然编译通过,但执行时会报一个错误。如图所示,这意味着你在除主线程外修改了UI界面,这个是android里面不允许的。所以有关UI界面的修改都要返回到主线程去修改。
EditText et = (EditText) MainActivity.this.findViewById(R.id.et);
et.setText(nums.toString());
这里写图片描述

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值