Handler,Looper,MessageQueue,ThreadLocal讲解以及实例

本文深入解析了Android消息机制的核心组件,包括Handler、Looper和MessageQueue的工作原理及其交互过程。介绍了如何在主线程与子线程间传递消息以更新UI,并通过示例代码展示了消息循环系统的实际应用。

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

Handler:是android消息机制的核心。一个线程可以有多个handler,但是只能有一个Looper和MessageQueue。handler是用来在线程间传递消息的。

而handler是发送消息以及传递消息的。在UI线程也是主线程,由于主线程会自动创建Looper,所以在子线程中,必须自己创建Looper才能创建Handler。

Handler的消息发送可以是handler.sendMessage()或者是handler.post(Runnable)。其中sendMessage()方法需要实现Handler的handleMessage方法,也就是消息的最终处理。

Looper是运行在创建Handler的那个线程中的。由于可以有多个handler,那么怎么知道消息的最终处理是交给那个handler的handleMessage中呢?

由于Message类中有个变量叫做target,message.target对应生成该message的handler,所以放在Looper处理时,就会转到对应的handleMessage中。

MessageQueue:是消息队列,但是它的实现是单链表,因为是要删除和添加,所以单链表的实现比较好,MessageQueue是由Looper.prapare()中实现的,其实也是Looper.parpare()方法调用Looper构造函数,由Looper构造函数中生成MessageQueue的。MessageQueue有两个方法,一个是enqueueMessage(),一个是next(),enqueueMessage()方法是插入Message,next()方法是读取一个Message,并且删除这个Message。其中next()方法是个无限循环的方法。

Looper:Looper叫做循环,由于MessageQueue只是用来存储Message的,而Looper则是用来处理Message的。Looper.loop()方法调用,才开始真正启动消息循环系统,在loop()中,会不断的调用messagequeue的next()方法,直到next()方法返回null则会停止。而next()不会主动自己返回null的,需要调用MessageQueue的quit()方法或者quitSafely()使得MessageQueue中的next()方法返回null,使得loop()方法中断。

ThreadLocal:不是线程,而是以线程为作用域的,各个线程之间互不干扰的一个数据存储类,用来存储Looper的,其中每个线程都有一个ThreadLocal.Values的变量来存储ThreadLocal的数据,其中是一个table数组。ThreadLocal的好处在于,1.线程之间互不干扰,否则需要设置一个通过handler查找looper的全局hash表。2.用在线程中的函数调用栈深的时候,需要在线程全程传递监听器,可以在该线程中设置一个ThreadLocal的全局变量。

整个流程是:在一般的Android消息机制中,先在主线程中创建一个handler,由于这个handler是在主线程中创建的,所以对应的主线程中本身存在的Looper,在子线程的耗时操作结束以后,需要将这个数据传递给主线程来更新UI,那么就直接调主线程的handler,通过handler.sendMessage()将消息插入到MessageQueue中,再由Looper来提取该消息,并处理,调用msg.target.dispatchMessage(msg),其中msg.target就是对应的handler,只是这个handler.dispatchMessage()方法是在主线程的Looper中执行的。也就实现了从子线程到主线程的传递。其中的MessageQueue和Looper都是主线程的。

以下是handler的实例

其中项目地址为:点击打开链接

package com.example.simmucheng.handlerdemo;

import android.os.Bundle;
import android.os.Handler;
import android.os.Looper;
import android.os.Message;
import android.support.v7.app.AppCompatActivity;
import android.view.View;
import android.widget.Button;
import android.widget.TextView;
import android.widget.Toast;

public class MainActivity extends AppCompatActivity {

    private Button Btn_start_sendmessage=null;
    private Button Btn_start_Runable=null;
    private Button Btn_from_main_to_thread=null;
    private Button Btn_stop=null;
    private TextView Tv_showtextview=null;
    private Handler ThreadHandler;

    Handler handler_main=new Handler();
    Handler handler_main_handlemessage=new Handler(){
        @Override
        public void handleMessage(Message msg) {
           // ThreadHandler.sendMessage(msg);
            Tv_showtextview.append("sendMessage = "+msg.arg1);
        }
    };

    Runnable MyRunnable=new Runnable() {
        @Override
        public void run() {
            Tv_showtextview.append("\nloading");
            handler_main.postDelayed(MyRunnable,1000);
        }
    };
    Handler handler1=new Handler(){
        @Override
        public void handleMessage(Message msg) {
            Tv_showtextview.append("\nheihei");
            Toast.makeText(MainActivity.this,"tttttt",Toast.LENGTH_SHORT).show();
        }
    };
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        initView();
        new MyThread().start();
        Btn_start_Runable.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                handler_main.post(MyRunnable);
            }
        });
        Btn_start_sendmessage.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                new Thread(){
                    @Override
                    public void run() {
                        Message msg=new Message();
                        msg.arg1=1;
                        msg.what=2;
                        handler1.sendMessage(msg);
                    }
                }.start();

            }
        });
        Btn_stop.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                handler_main.removeCallbacks(MyRunnable);
            }
        });
        Btn_from_main_to_thread.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                Message msg1=new Message();
                msg1.arg1=3;
                ThreadHandler.sendMessage(msg1);
            }
        });
    }

    private void initView() {
        Btn_start_sendmessage= (Button) findViewById(R.id.Start_Handler_sendmessage);
        Btn_from_main_to_thread= (Button) findViewById(R.id.from_main_to_thread);
        Btn_start_Runable= (Button) findViewById(R.id.Start_Handler_Runable);
        Btn_stop= (Button) findViewById(R.id.stop);
        Tv_showtextview= (TextView) findViewById(R.id.ShowTextView);
    }

    class MyThread extends Thread{
        @Override
        public void run() {
            Looper.prepare();
            ThreadHandler=new Handler(Looper.myLooper()){
                @Override
                public void handleMessage(Message msg) {
                    msg.arg1+=1000;
                    Message msg1=handler_main_handlemessage.obtainMessage();
                    msg1.arg1=msg.arg1;
                    handler_main_handlemessage.sendMessage(msg1);
                    // 这个里面,在sendMessage(message)之后,会标记该message的isInUse=true
                    //所以要想再次sendMessage该message,需要重新obtainMessage得到新的message,这样
                    //得到的message的isInUse会被取消
                }
            };
            Looper.loop();
        }


    }
}

其中enqueueMessage的局部代码,显示会将message标记为已经加入队列。所以有的时候不注意会出现in use的错误。

boolean enqueueMessage(Message msg, long when) {
        if (msg.target == null) {
            throw new IllegalArgumentException("Message must have a target.");
        }
        if (msg.isInUse()) {
            throw new IllegalStateException(msg + " This message is already in use.");
        }

        synchronized (this) {
            if (mQuitting) {
                IllegalStateException e = new IllegalStateException(
                        msg.target + " sending message to a Handler on a dead thread");
                Log.w(TAG, e.getMessage(), e);
                msg.recycle();
                return false;
            }

            <span style="color:#ff0000;">msg.markInUse();</span>
            msg.when = when;
            Message p = mMessages;
      }
}

    /*package*/ boolean isInUse() {
        return ((flags & FLAG_IN_USE) == FLAG_IN_USE);
    }

    /*package*/ void markInUse() {
        flags |= FLAG_IN_USE;
    }


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值