ICode9

精准搜索请尝试: 精确搜索
首页 > 其他分享> 文章详细

Handler机制相关流程

2022-03-01 16:30:00  阅读:180  来源: 互联网

标签:MessageQueue 流程 Handler Looper msg new Message 机制


Handler:发送和接收消息
Looper :轮询循环消息队列,一个线程只有一个Looper
Message:消息的实体
MessageQueue:主要是存储消息和管理消息

创建Looper:

//ActivityThread.java
public static void main(String[] args) {
        Trace.traceBegin(Trace.TRACE_TAG_ACTIVITY_MANAGER, "ActivityThreadMain");
 		//此处省略代码
        Looper.prepareMainLooper();//初始化Looper和messagQueue
        if (false) {
            Looper.myLooper().setMessageLogging(new
                    LogPrinter(Log.DEBUG, "ActivityThread"));
        }
        // End of event ActivityThreadMain.
        Trace.traceEnd(Trace.TRACE_TAG_ACTIVITY_MANAGER);
        Looper.loop();//用于循环消息
        throw new RuntimeException("Main thread loop unexpectedly exited");
    }
//Looper.java
  public static void prepareMainLooper() {
   	//消息队列不可以quit
       prepare(false);
       synchronized (Looper.class) {
           if (sMainLooper != null) {
               throw new IllegalStateException("The main Looper has already been prepared.");
           }
           sMainLooper = myLooper();
       }
   }
/**
prepare有两个重载的方法,主要是看prepare(boolean quitAllowed) 作用是在创建出MessageQueue时后标识消息队列是否可以被销毁,
但是在主线程中时不会被销毁的
*/
 public static void prepare() {
        prepare(true);
    }

 private static void prepare(boolean quitAllowed) {
      //quitAllowed 
 	  //sThreadLocal.get()不为空表示已经创建出Looper
      if (sThreadLocal.get() != null) {
           throw new RuntimeException("Only one Looper may be created per thread");
           //每个线程只能创建出一个Looper
       }
       //这个地方就是创建出Looper,并且存放到sThreadLocal中
       sThreadLocal.set(new Looper(quitAllowed));
 }

MessageQueue创建以及如何绑定Looper

    private Looper(boolean quitAllowed) {
    	//创建MessageQueue
        mQueue = new MessageQueue(quitAllowed);
        //与当前的线程进行绑定
        mThread = Thread.currentThread();
    }
    MessageQueue(boolean quitAllowed) {
    	//quitAllowed表示是队列是否可以被销毁,主线程的队列不可以被销毁需要传入false
        mQuitAllowed = quitAllowed;
        mPtr = nativeInit();
    }

Looper.looop()

public static void loop() {
        final Looper me = myLooper();//从sThreadLocal中获取到创建出的looper对象
        if (me == null) {
            throw new RuntimeException("No Looper; Looper.prepare() wasn't called on this thread.");
        }
        final MessageQueue queue = me.mQueue;
        Binder.clearCallingIdentity();
        final long ident = Binder.clearCallingIdentity();

        boolean slowDeliveryDetected = false;
        for (;;) {
        	//死循环表示会一直去查询消息
            Message msg = queue.next(); // might block
            if (msg == null) {
                // No message indicates that the message queue is quitting.
                // 队列里面没有消息,需要等待MessageQueue发送消息
                return;
            }

            if (traceTag != 0 && Trace.isTagEnabled(traceTag)) {
                Trace.traceBegin(traceTag, msg.target.getTraceName(msg));
            }

            final long dispatchStart = needStartTime ? SystemClock.uptimeMillis() : 0;
            final long dispatchEnd;
            try {
                //查询到消息后,然后会去回调到Handler中的dispatchMessage中
                msg.target.dispatchMessage(msg);
                dispatchEnd = needEndTime ? SystemClock.uptimeMillis() : 0;
            } finally {
                if (traceTag != 0) {
                    Trace.traceEnd(traceTag);
                }
            }
		//后面代码省略......
    }

创建handler

	//常见的Hanlder的创建方式
     Handler handler = new Handler(){
        @Override
        public void handleMessage(@NonNull Message msg) {
            super.handleMessage(msg);
        }
    };
    public Handler(@Nullable Callback callback, boolean async) {
   	    //获取Looper,这个是从sThreadLocal中获取到的
        mLooper = Looper.myLooper();
        if (mLooper == null) {
            throw new RuntimeException(
                "Can't create handler inside thread " + Thread.currentThread()
                        + " that has not called Looper.prepare()");
        }
        //创建出消息队列MessageQueue
        mQueue = mLooper.mQueue;
        //初始化回调
        mCallback = callback;
        mAsynchronous = async;
    }

Looper.myLooper()

Looper.java
	//主要是处理多线程并发的问题
	static final ThreadLocal<Looper> sThreadLocal = new ThreadLocal<Looper>();
	
	//获取对于的Looper对象,必须先要调用prepare()方法进行创建
    public static @Nullable Looper myLooper() {
        return sThreadLocal.get();
    }

创建Message

Message.java
       1. Message message = new Message();
       2. Message obtain = Message.obtain();
       
       //使用Message.obtain比直接new出来的Message要好,可以避免多次创建,销毁message对象优化内存和性能的目的
       public static Message obtain() {
       //用来同步,保证线程安全
        synchronized (sPoolSync) {
        	//回收和复用Handler
            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();
    }

Message与Handler的绑定
创建Message的时候可以通过Message.obtain(Handler h)这个构造函数去绑定,也可以在Handler enqueueMessage中去绑定,所有发送的Message消息都会调用此方法入队,所以在创建Message的时候可以不去绑定。


private boolean enqueueMessage(@NonNull MessageQueue queue, @NonNull Message msg,
            long uptimeMillis) {
        msg.target = this;//绑定
        msg.workSourceUid = ThreadLocalWorkSource.getUid();

        if (mAsynchronous) {
            msg.setAsynchronous(true);
        }
        return queue.enqueueMessage(msg, uptimeMillis);
    }

Handler发送消息
Handler发送的消息重载方法很多,但常用的只有两种。sendMessage(Message)方法通过一系列的重载方法调用如下流程:

 //1.入口
 handler.sendMessage(Message);
 //调用到sendMessage
 public final boolean sendMessage(@NonNull Message msg) {
        return sendMessageDelayed(msg, 0);
 }
//2.调用sendMessageDelayed
 public final boolean sendMessageDelayed(@NonNull Message msg, long delayMillis) {
        if (delayMillis < 0) {
            delayMillis = 0;
        }
        return sendMessageAtTime(msg, SystemClock.uptimeMillis() + delayMillis);
 }

 //3.调用到sendMessageAtTime
 public boolean sendMessageAtTime(@NonNull 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);
 }

//4.调用到enqueueMessage
private boolean enqueueMessage(@NonNull MessageQueue queue, @NonNull Message msg,
            long uptimeMillis) {
        msg.target = this;
        msg.workSourceUid = ThreadLocalWorkSource.getUid();

        if (mAsynchronous) {
            msg.setAsynchronous(true);
        }
        return queue.enqueueMessage(msg, uptimeMillis);
 }

//5.调用到enqueueMessage
//将消息保存在消息队列中,最终又Looper取出,交给Handler的dispatchMessage进行处理
 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;
            }

            msg.markInUse();
            //延迟时间
            msg.when = when;
            //获取到消息的第一个元素
            Message p = mMessages;
            boolean needWake;
            if (p == null || when == 0 || when < p.when) {
                // New head, wake up the event queue if blocked.
                //如果此队列中头部元素是null(空的队列,一般是第一次),或者此消息不是延时的消息,则此消息需要被立即处理,
                //此时会将这个消息作为新的头部元素,然后判断如果Looper获取消息的线程如果是阻塞状态则唤醒它,让它立刻去拿消息处理
                msg.next = p;
                mMessages = msg;
                needWake = mBlocked;
            } else {
            //如果此消息是延时的消息,则将其添加到队列中,原理就是链表的添加新元素,按照when,也就是延迟的时间来插入的,延迟的时间越长,
            //越靠后,这样就得到一条有序的延时消息链表,取出消息的时候,延迟时间越小的,就被先获取了.
                needWake = mBlocked && p.target == null && msg.isAsynchronous();
                Message prev;
                for (;;) {
                    prev = p;
                    p = p.next;
                    if (p == null || when < p.when) {
                        break;
                    }
                    if (needWake && p.isAsynchronous()) {
                        needWake = false;
                    }
                }
                msg.next = p; // invariant: p == prev.next
                prev.next = msg;
            }

            // We can assume mPtr != 0 because mQuitting is false.
            if (needWake) {//唤醒线程
                nativeWake(mPtr);
            }
        }
        return true;
    }
	
    public void dispatchMessage(@NonNull Message msg) {
   		 //callback在Message的构造方法中初始化和使用
        if (msg.callback != null) {
            handleCallback(msg);
        } else {
            if (mCallback != null) {
            	//最终回调到上层执行handlerMessage方法
                if (mCallback.handleMessage(msg)) {
                    return;
                }
            }
            handleMessage(msg);
        }
    }

Handler处理消息
在handlerMessage(Message)方法中,我们就可以拿到Message对象,然后进行处理,整个Handler的流程就结束了

    Handler handler = new Handler(){
        @Override
        public void handleMessage(@NonNull Message msg) {
        	//获取Message,进行处理
            super.handleMessage(msg);
        }
    };

总结
Handler的大致流程如上步骤。 从handler.sendMassge发送消息到消息队列MessageQueue,然后调用looper调用到自己loop()函数带动MessageQueue从而去轮询MessageQueue里面的每个Message,当Message达到了可以执行的时间的时候开始执行,执行后会调用Message绑定的Handler来处理消息。

标签:MessageQueue,流程,Handler,Looper,msg,new,Message,机制
来源: https://blog.csdn.net/qq_42989195/article/details/123191045

本站声明: 1. iCode9 技术分享网(下文简称本站)提供的所有内容,仅供技术学习、探讨和分享;
2. 关于本站的所有留言、评论、转载及引用,纯属内容发起人的个人观点,与本站观点和立场无关;
3. 关于本站的所有言论和文字,纯属内容发起人的个人观点,与本站观点和立场无关;
4. 本站文章均是网友提供,不完全保证技术分享内容的完整性、准确性、时效性、风险性和版权归属;如您发现该文章侵犯了您的权益,可联系我们第一时间进行删除;
5. 本站为非盈利性的个人网站,所有内容不会用来进行牟利,也不会利用任何形式的广告来间接获益,纯粹是为了广大技术爱好者提供技术内容和技术思想的分享性交流网站。

专注分享技术,共同学习,共同进步。侵权联系[81616952@qq.com]

Copyright (C)ICode9.com, All Rights Reserved.

ICode9版权所有