美文网首页
Handler源码分析

Handler源码分析

作者: 陈道乐 | 来源:发表于2020-03-05 19:41 被阅读0次

使用

    class MyRunnable implements Runnable {
        private Handler handler = null;

        Handler getHandler() {
            return handler;
        }

        @Override
        public void run() {
            Looper.prepare();
            handler = new Handler() {
                @Override
                public void handleMessage(@NonNull Message msg) {
                    super.handleMessage(msg);
                }
            };
            Looper.loop();
        }
    }
    
    MyRunnable runnable = new MyRunnable();
    Thread thread = new Thread(runnable);
    thread.start();
    Handler handler = runnable.getHandler();
    if (handler != null) {
        handler.post(new Runnable {
            @Override
            public void run() {
               //抛到线程中处理任务
            }
        });
    }
    
    //发送消息到线程中处理
    handler.sendMessage();

Loop.prepare

首先在使用 handler 之前我们都需要这样初始化, 在Android UI主线程中是隐式处理的。

    //线程的本地变量,这个是个好东西,只能获取到当前线程保存的变量
    static final ThreadLocal<Looper> sThreadLocal = new ThreadLocal<Looper>();
    
    public static void prepare() {
        prepare(true);
    }

    //看这个函数就好了
    private static void prepare(boolean quitAllowed) {
        //先检查一下是否已经初始化了
        if (sThreadLocal.get() != null) {
            throw new RuntimeException("Only one Looper may be created per thread");
        }
        
        //然后创建一个循环, 我们看一下Looper的代码
        sThreadLocal.set(new Looper(quitAllowed));
    } 
    
    
    final class Looper {
        @UnsupportedAppUsage
        final MessageQueue mQueue;
        final Thread mThread;
        
        //实质上是创建一个消息队列,保存一下当前线程的引用
        private Looper(boolean quitAllowed) {
            mQueue = new MessageQueue(quitAllowed);
            mThread = Thread.currentThread();
        }

    }
  

Looper.loop

开始循环操作, 就是这么简单,当然 还是有很多参数,需要我们去看的

    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;

        //我也没怎么看懂,有点像获取当前进程的身份ID的意思
        // Make sure the identity of this thread is that of the local process,
        // and keep track of what that identity token actually is.
        Binder.clearCallingIdentity();
        final long ident = Binder.clearCallingIdentity();

        // Allow overriding a threshold with a system prop. e.g.
        // adb shell 'setprop log.looper.1000.main.slow 1 && stop && start'
        final int thresholdOverride =
                SystemProperties.getInt("log.looper."
                        + Process.myUid() + "."
                        + Thread.currentThread().getName()
                        + ".slow", 0);

        boolean slowDeliveryDetected = false;

        //接下来启动一个循环处理消息
        for (;;) {
            //获取消息的过程是一个可能堵塞的过程,注意是可能,如果真的获取到空的消息意味着退出
            Message msg = queue.next(); // might block
            if (msg == null) {
                // No message indicates that the message queue is quitting.
                return;
            }

             //日志消息没什么好看的
            // This must be in a local variable, in case a UI event sets the logger
            final Printer logging = me.mLogging;
            if (logging != null) {
                logging.println(">>>>> Dispatching to " + msg.target + " " +
                        msg.callback + ": " + msg.what);
            }
            // Make sure the observer won't change while processing a transaction.
            final Observer observer = sObserver;

            final long traceTag = me.mTraceTag;
            long slowDispatchThresholdMs = me.mSlowDispatchThresholdMs;
            long slowDeliveryThresholdMs = me.mSlowDeliveryThresholdMs;
            if (thresholdOverride > 0) {
                slowDispatchThresholdMs = thresholdOverride;
                slowDeliveryThresholdMs = thresholdOverride;
            }
            final boolean logSlowDelivery = (slowDeliveryThresholdMs > 0) && (msg.when > 0);
            final boolean logSlowDispatch = (slowDispatchThresholdMs > 0);

            final boolean needStartTime = logSlowDelivery || logSlowDispatch;
            final boolean needEndTime = logSlowDispatch;

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

            final long dispatchStart = needStartTime ? SystemClock.uptimeMillis() : 0;
            final long dispatchEnd;
            Object token = null;
            if (observer != null) {
                token = observer.messageDispatchStarting();
            }
            long origWorkSource = ThreadLocalWorkSource.setUid(msg.workSourceUid);
            try {
                //target指的就是handler,这个就是分发消息的东西了, 核心应该是这个部分
                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);
                }
            }
            if (logSlowDelivery) {
                if (slowDeliveryDetected) {
                    if ((dispatchStart - msg.when) <= 10) {
                        Slog.w(TAG, "Drained");
                        slowDeliveryDetected = false;
                    }
                } else {
                    if (showSlowLog(slowDeliveryThresholdMs, msg.when, dispatchStart, "delivery",
                            msg)) {
                        // Once we write a slow delivery log, suppress until the queue drains.
                        slowDeliveryDetected = true;
                    }
                }
            }
            if (logSlowDispatch) {
                showSlowLog(slowDispatchThresholdMs, dispatchStart, dispatchEnd, "dispatch", msg);
            }

            if (logging != null) {
                logging.println("<<<<< Finished to " + msg.target + " " + msg.callback);
            }

            // Make sure that during the course of dispatching the
            // identity of the thread wasn't corrupted.
            final long newIdent = Binder.clearCallingIdentity();
            if (ident != newIdent) {
                Log.wtf(TAG, "Thread identity changed from 0x"
                        + Long.toHexString(ident) + " to 0x"
                        + Long.toHexString(newIdent) + " while dispatching to "
                        + msg.target.getClass().getName() + " "
                        + msg.callback + " what=" + msg.what);
            }

            msg.recycleUnchecked();
        }
    }
    
    public final class MessageQueue {
        Message next() {
            ...
            ...
            //暴力的循环获取
            for (;;) {
                ...
                ...
                //能看到这个是一个同步的操作
                synchronized (this) {
                }
                ...
                ...
            }
        }
        
        //消息入队的操作
        boolean enqueueMessage(Message msg, long when) {
            ...
            ...
            //同步入队
            synchronized (this) {
                ...
                ...
                //有意思的是我们可以看到队列的结构是单向链式
            }
            ...
            ...
        }
    }

Handler

到这里就是使用部分了

public class Handler {
    
    //post 和 postDelay方法使用的都是直接调用这个方法,所以重点关注一下
    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);
    }
    
    
    private boolean enqueueMessage(@NonNull MessageQueue queue, @NonNull Message msg,
            long uptimeMillis) {
            
        //这边我们可以看到target实际上指的就是handler    
        msg.target = this;
        msg.workSourceUid = ThreadLocalWorkSource.getUid();

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

总结

简单的过了一下源码,能看到其实很多参数没有提及,这个需要实际应用的时候才知道,大致就是使用线程标记一个循环,并且,启动循环, Handler实际上是和循环挂钩的, 通过向循环抛入消息的方式,在线程之间传递消息。

相关文章

网友评论

      本文标题:Handler源码分析

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