Handler

作者: 放肆滴微笑 | 来源:发表于2020-06-30 10:24 被阅读0次

    在程序的入口

    public static void main(String[] args) {
            ...
    
            Looper.prepareMainLooper();
    
            // Find the value for {@link #PROC_START_SEQ_IDENT} if provided on the command line.
            // It will be in the format "seq=114"
            long startSeq = 0;
            if (args != null) {
                for (int i = args.length - 1; i >= 0; --i) {
                    if (args[i] != null && args[i].startsWith(PROC_START_SEQ_IDENT)) {
                        startSeq = Long.parseLong(
                                args[i].substring(PROC_START_SEQ_IDENT.length()));
                    }
                }
            }
            // 可以看成一个线程
            ActivityThread thread = new ActivityThread();
    
            // ams 和 当前进程 进行一个绑定
            thread.attach(false, startSeq);
    
            if (sMainThreadHandler == null) {
                sMainThreadHandler = thread.getHandler();
            }
    
            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");
        }
    

    程序启动,到结束,main方法就结束了,但是app结束,就退出程序了,所以不能结束,Looper.loop(); 可以看成一个死循环
    如果要结束程序,要loop结束,handler接收到消息,就会结束

     case EXIT_APPLICATION:
                        if (mInitialApplication != null) {
                            mInitialApplication.onTerminate();
                        }
                        Looper.myLooper().quit(); // 退出loop
    

    系统Handler
    客户端Handler

    final H mH = new H(); // 饿汉式加载,直接初始化
    
    handleMessage 方法中接收系统的消息,4大组件生命周期,都是通过发消息Handler来处理
    

    我们来看Looper.loop();

    public static void loop() {
            // 获取  消息泵
            final Looper me = myLooper();
           // 消息泵中有一个消息队列
            final MessageQueue queue = me.mQueue;
    
            ...
            // 进行死循环
            for (;;) {
                Message msg = queue.next(); // 注释1
                // 如果没有消息,则继续循环
                if (msg == null) {
                    // No message indicates that the message queue is quitting.
                    return;
                }
    
                ...
                // 获取到消息,并进行派发target 就是handler  注释2
                try {
                    msg.target.dispatchMessage(msg);
                    if (observer != null) {
                        observer.messageDispatched(token, msg);
                    }
                    dispatchEnd = needEndTime ? SystemClock.uptimeMillis() : 0;
                } catch (Exception exception) {
                    if (observer != null) {
                        observer.dispatchingThrewException(token, msg, exception);
                    }
                    throw exception;
                } finally {
                    ThreadLocalWorkSource.restore(origWorkSource);
                    if (traceTag != 0) {
                        Trace.traceEnd(traceTag);
                    }
                }
                ...
                // 进行消息的回收处理
                msg.recycleUnchecked();
            }
        }
    

    我们看looper 就一只在循环,当在队列中没有消息继续循环,有了消息,看到注释1 处,进行获取消息,注释2处,进行派发消息
    获取消息,并不是队列的先进先出,因为消息带有时间,根据时间判断,如果当前时间小于消息时间,就先不发送,大于当前时间,则按队列顺序发送

    # 进行获取消息,是在MessageQueue.java
    
    @UnsupportedAppUsage
        Message next() {
            ...
            //  也是个死循环,因为消息有时间,没到就等到时间
            for (;;) {
                if (nextPollTimeoutMillis != 0) {
                    Binder.flushPendingCommands();
                }
    
                nativePollOnce(ptr, nextPollTimeoutMillis);
    
                synchronized (this) {
                    ...
                    if (msg != null) {
                        // 当前时间 和 消息时间比较
                        if (now < msg.when) {
                            // Next message is not ready.  Set a timeout to wake up when it is ready.
                            nextPollTimeoutMillis = (int) Math.min(msg.when - now, Integer.MAX_VALUE);
                        } else {
                            // Got a message.
                            mBlocked = false;
                            if (prevMsg != null) {
                                prevMsg.next = msg.next;
                            } else {
                                mMessages = msg.next;
                            }
                            msg.next = null;
                            if (DEBUG) Log.v(TAG, "Returning message: " + msg);
                            msg.markInUse();
                            return msg;
                        }
                    } else {
                        // No more messages.
                        nextPollTimeoutMillis = -1;
                    }
                  ...
            }
        }
    

    进行派发消息

    # 注释2处,进行派发消息
    # Handler
    public void dispatchMessage(@NonNull Message msg) {
            // callback 其实就一个 Runnable
            if (msg.callback != null) {
                handleCallback(msg);
            } else {
                if (mCallback != null) {
                    if (mCallback.handleMessage(msg)) {
                        return;
                    }
                }
                // 当没有Runnable  则调用自己重写的handleMessage方法,里面是空的
                handleMessage(msg);
            }
        }
    // 相当于调用了 Runnable 的run方法,其实还是在当前线程执行
    private static void handleCallback(Message message) {
            message.callback.run();
    }
    
    # Message
    Runnable callback;
    

    上述写法 ,相当于派发了消息,如果有Callback,就执行run,没有就执行 handleMessage

    Handler handler = new Handler();
        int i = 0;
        Runnable run = new Runnable() {
            @Override
            public void run() {
                Log.e(TAG, "run: " + i++);
                handler.postDelayed(run, 1000);
                if(i == 10){
                    handler.removeCallbacks(run);
                }
            }
        };
    
    
     handler.post(run);
    

    handler的发送消息,是可以带时间的,分为马上发,或者延迟发,发送消息的时候,消息是从消息吃中取,当前开始也没有,也是new出来的,当handler执行完消息派发,则在loop方法中调用msg.recycleUnchecked();来进行回收

    # message
    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();
        }
    
    # handler
    //uptimeMillis  就是这条消息的时间
    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);
        }
    

    消息 一种有Runnable 一种是没有

    因为是多线程的,每个线程都会访问同一个message,所以会出现问题,就出现了ThreadLocal,里面放的就是Looper

    handler 可以这样理解,
    要使用handler,就需要进行Looper.prepare();Looper.loop();子线程中使用如下,

    class LooperThread extends Thread {
            public Handler mHandler;
    
            public void run() {
                Looper.prepare();
    
                mHandler = new Handler() {
                    public void handleMessage(Message msg) {
                        // process incoming messages here
                    }
                };
    
                Looper.loop();
            }
        }
    

    主线程之所以不用,是因为主线程中系统已经写了
    Looper.prepareMainLooper();之后又有Looper.loop();

    handler在系统中存在2中通信,1系统的,Activity的生命周期,2自己写的,为什么自己写的不可以像系统handler发消息呢?
    因为handler 是通过ThreadLocal这个类进行封装,里面包含了<Loop>,loop中又有Thread当前线程,MessageQueue消息队列,handler通过发送消息发送到当前线程的MessageQueue中,又从中取消息,这样就不会发送到系统里面了
    handler 容易造成内存泄露,我们可以在handler post的时候弄个Runnable,之后再Activity结束时候,进行handler.removeCallbacks(run);// 移除创建的Runnable

    相关文章

      网友评论

          本文标题:Handler

          本文链接:https://www.haomeiwen.com/subject/klpegctx.html