Andriod中Handler原理

Handler是一种异步回调机制,用于线程间消息传递。涉及Handler、MessageQueue、Message和Looper。主线程默认有Looper,子线程需手动准备。消息通过Message封装,由Handler发送到MessageQueue,Looper循环取出并由Handler处理。Message池优化了对象创建。

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

Handler处理机制

概念:

​ Handler是一种异步回调机制,也可以看作是线程之间的消息传递机制。对一些耗时操作放在另一个子线程中进行,子线程完成之后,将结果返回给主线程,主线程对其结果进行UI操作,即完成了主线程和子线程之间的线程信息传递。

涉及到的几个重要职责类:

Handler:负责消息Message的传递,分发以及处理等操作。

MessageQueue:消息队列,负责暂时缓存子线程发送过来的信息

Message:消息的封装类

Looper:循环从消息队列中拿出消息,交给handler进行处理

ThreadLocal:实现线程中的数据隔离性,每个线程中独有的数据可以放在这里面,避免其他线程修改。

Handler内部机制原理:

​ 首先,正常情况下在主线程中对共享的Hander对象进行声明,然后主线程中进行实例化,并对其进行接受消息处理(重写方法)。开启子线程进行耗时操作,完成后进行数据传递

private Handler mHandler;
mHandler = new Handler(){
        @Override
        public void handleMessage(Message msg) {
            super.handleMessage(msg);
            //接受子线程传递过来的消息,在主线中进行逻辑处理
          }
    };
    
    private void sendMessageToMainThreadByWorkThread() {
        new Thread(){
            @Override
            public void run() {
                //耗时操作
                //从消息池中返回消息对象,避免消息的重复创建
                Message message = mHandler.obtainMessage(MESSAGE_WHAT);
                //将子线程的操作结果放入消息封装类中的Object对象中
                message.obj = "I am message from work thread";
                //handler对象将消息发送给消息队列中,供主线中进行取出。
                mHandler.sendMessage(message);
            }
        }.start();
    }


public final boolean sendMessage(Message msg)
    {
        return sendMessageDelayed(msg, 0);
    }
//==========================================================================
 public final boolean sendMessageDelayed(Message msg, long delayMillis)
    {
        if (delayMillis < 0) {
            delayMillis = 0;
        }
        return sendMessageAtTime(msg, SystemClock.uptimeMillis() + delayMillis);
    }
//==========================================================================
  public boolean sendMessageAtTime(Message msg, long uptimeMillis) {
        MessageQueue queue = mQueue;
        if (queue == null) {
            RuntimeException e = new RuntimeException(
                    this + " sendMessageAtTime() called with no mQueue");
            Log.w("Looper", e.getMessage(), e);
            return false;
        }
        return enqueueMessage(queue, msg, uptimeMillis);
    }
//==========================================================================
 private boolean enqueueMessage(MessageQueue queue, Message msg, long uptimeMillis) {
        msg.target = this;
        if (mAsynchronous) {
            msg.setAsynchronous(true);
        }
     //最终消息发送这个动作,还是在handler对象中调用消息队列的消息进队方法实现
        return queue.enqueueMessage(msg, uptimeMillis);
    }

还记得Looper类吗?之前说主线程是靠这个类从消息队列中进行循环取出消息,然后交给handler类进行消息处理,但是这边却没有看到looper的出现,这是为什么?

解释这个问题前,先理解一个东西:在handler机制中,上述方法的基本给出了从发送消息–》消息进入消息队列,底层过程。 但是取出消息,处理消息,是完全不一样的。任何线程从消息队列中取出消息都是依靠looper类的,looper类中的loop()实现了从消息队列中循环取出消息(后面介绍),因此如果一个线程想要从消息队列中获取消息,就必须要实现自己的Looper类,那么为什么主线程没有Looper类的实现?

通过底层代码,可以发现,原来主线程进行初始化的时候,就已经对Looper类自动实现.

ActivityThread类中,主方法:

 public static void main(String[] args) {
      //省略

        Looper.prepareMainLooper();
//省略
        Looper.loop();
//省略
    }

可以发现主方法里面调用了Looper.prepareMainLooper();和Looper.loop();这个两个方法。

   public static void prepareMainLooper() {
        prepare(false);
        synchronized (Looper.class) {
            if (sMainLooper != null) {
                throw new IllegalStateException("The main Looper has already been prepared.");
            }
            sMainLooper = myLooper();
        }
    }

//=======================================================
 private static void prepare(boolean quitAllowed) {
        if (sThreadLocal.get() != null) {
            throw new RuntimeException("Only one Looper may be created per thread");
        }
     //创建了一个Looper对象,并且将对象赋值给当前线程的ThreadLocal对象中,作为隔离数据
        sThreadLocal.set(new Looper(quitAllowed));
    }
//=======================================================
//对Looper类进行实例化时,会对消息队列也同时进行实例化
  private Looper(boolean quitAllowed) {
        mQueue = new MessageQueue(quitAllowed);
        mThread = Thread.currentThread();
    }

//====================================
public static @Nullable Looper myLooper() {
        return sThreadLocal.get();//返回一个与主线程相关联的Looper对象
    }

//---------------------------------------------------------------
//loop()函数,
  public static void loop() {
    //省略一堆系统的安全检查逻辑
      		//一个死循环,只有当消息队列没有任何消息对象时,才会退出。
        for (;;) {
            Message msg = queue.next(); // might block
            if (msg == null) {
                // No message indicates that the message queue is quitting.
                return;
            }
            //循环取出消息的算法
        }
    }

通过上述两个方法可以知道,如果不是主线程进行消息的接收,那么需要在handlerMessage()方法之前,调用上述方法

private Handler handler;
    private void handlerDemoByTwoWorkThread() {
        Thread ThreadA = new Thread() {
            @Override
            public void run() {
                Looper.prepare();//因为不是主函数,因此可以调用这个,创建Looper对象,同时和当前线程进行绑定
                handler = new Handler() {//给出了handler实例,同时重写了处理消息的逻辑
                    @Override
                    public void handleMessage(Message msg) {
                        //逻辑处理
                };
                Looper.loop();//从消息队列中将消息循环取出。
            }
        };

这样的话基本了解了Message作为封装类、MessageQueue作为消息暂时存储的地方,ThreadLocal类存储每个线程自己的Looper对象引用,保证了每个线程拥有自己的取数据对象。

Handler机制的接发流程

Handler对象的具体流程,

发送消息的处理流程基本没啥可说的,就是通过共享的handler对象,调用其中的obtainMessage()方法,从消息队列中获取消息封装对象,然后将结果存储在消息封装对象的对应属性中,最后通过调用sendMessage(Message msg)方法进行消息的传递。底层实现上面有介绍。

着重记录以下线程如何从消息队列中拿出消息:

Looper的创建,绑定。以及loop()方法循环拿数据,前面提过一下,这里看一下loop()函数,取数据的逻辑操作,取出数据后如何将数据给到handler对象中,进行内容的处理。

public static void loop() {
        final Looper me = myLooper();
        if (me == null) {
            throw new RuntimeException("No Looper; Looper.prepare() wasn't called on this thread.");
        }
        final MessageQueue queue = me.mQueue;
        for (;;) {
            Message msg = queue.next(); // might block
            if (msg == null) {
                // No message indicates that the message queue is quitting.
                return;
            }

           //循环取出的算法
            try {
                //调用消息本体的target属性中的dispatchMessage(msg)方法来进行消息的处理
                msg.target.dispatchMessage(msg);
                //.............
            } finally {
               //.............
            }
           //.......
        }
    }

loop()方法取出消息之后,会调用该方法的target属性,

/*package*/ Handler target;

通过查看消息封装类中的代码,可以看到target是一个handler对象的声明。也就是意味着,每一个产生的消息都可以指定不动的handler来进行处理,这就是为什么一个线程可以有多个handler(一个线程可以产生很多的消息,通过指定,可以为每个消息实体绑定不同的handler处理对象。)

总结:loop()方法取到了消息,通过该消息的target属性,获得对应的handler处理对象,调用handler对象的dispatchMessage(msg)方法,将消息进行分发,具体处理逻辑:先看消息本身是否有回调方法,如果没有看handler是否有回调方法,如果上述都没有,则会调用handler本身的handleMessage方法。

    public void dispatchMessage(Message msg) {
        if (msg.callback != null) {
            //如果,通过obtainMessage获得的Message对象,进行了setcallback(Runnable r)的话,会调用消息自身的回调方法进行处理。----》消息对象自己实现回调后的逻辑处理
            handleCallback(msg);
        } else {
            if (mCallback != null) {
                if (mCallback.handleMessage(msg)) {
                    //如果实例化Handler的时候,传递了Callback对象的话,那么回调会调用callback中所实现的handleMessage(msg)方法,
                    return;
                }
            }
            //调用子类重写的handleMessage(msg)方法,如果子类不重写的话,是一个无实现体的方法
            handleMessage(msg);
        }
    }

存取的流程图

存取流程图,结合上述文字,来理解。

最后补充:

消息的创建,使用了消息池,

    public static Message obtain() {
        synchronized (sPoolSync) {
            if (sPool != null) {
                Message m = sPool;
                sPool = m.next;
                m.next = null;
                m.flags = 0; // clear in-use flag
                sPoolSize--;
                return m;
            }
        }
        return new Message();
    }

在创建消息时会先从消息池中去查询是否有消息对象,如果有,则直接使用消息池中的对象,如果没有,则创建一个新的消息对象。

使用ThreadLocal的目的是保证每一个线程只创建唯一一个Looper。之后其他Handler初始化的时候直接获取第一个Handler创建的Looper。

public static @Nullable Looper myLooper() {
        return sThreadLocal.get();
    }

//==========================
public Handler(Callback callback, boolean async) {
        if (FIND_POTENTIAL_LEAKS) {
            final Class<? extends Handler> klass = getClass();
            if ((klass.isAnonymousClass() || klass.isMemberClass() || klass.isLocalClass()) &&
                    (klass.getModifiers() & Modifier.STATIC) == 0) {
                Log.w(TAG, "The following Handler class should be static or leaks might occur: " +
                    klass.getCanonicalName());
            }
        }

        mLooper = Looper.myLooper();//如果创建其他的Hander对象的话,其他handler对象的获取数据也是通过当前线程的唯一Looper线程来操作的
        if (mLooper == null) {
            throw new RuntimeException(
                "Can't create handler inside thread " + Thread.currentThread()
                        + " that has not called Looper.prepare()");
        }
        mQueue = mLooper.mQueue;
        mCallback = callback;
        mAsynchronous = async;
    }
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值