Android Handler机制

作者: 卖炭少年炭治郎 | 来源:发表于2020-05-06 08:05 被阅读0次

    行到水穷处,坐看云起时。-->王维

    handler是如何创建的?

    1. 我们先在子线程中创建一个handler,代码如下:
    new Thread(new Runnable() {
                @Override
                public void run() {
                    Handler handler = new Handler();
                }
            }).start();
    

    运行会抛出

    Can't create handler inside thread Thread[Thread-2,5,main] that has
    not called Looper.prepare()

    异常。跟踪到handler的构造方法里发现

    public Handler(@Nullable 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());
                }
            }
    //取存储在sThreadLocal中的looper()对象
            mLooper = Looper.myLooper();
            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;
        }
    

    当你new handler()的时候,并没有Looper,导致抛出了异常。

    new Thread(new Runnable() {
                @Override
                public void run() {
                //先通过这个静态方法创建looper,并存储在sThreadLocal中.
                    Looper.prepare();
                    Handler handler = new Handler();
                }
            }).start();
    
    • 在Looper.prepare()方法调用时,创建looper,并存储在sThreadLocal中。
    • 在looper构造方法中,又创建了MessageQueue。
    private Looper(boolean quitAllowed) {
            mQueue = new MessageQueue(quitAllowed);
            mThread = Thread.currentThread();
        }
    

    以上我们就创建好了messageQueue,Looper和Handler,可以愉快的玩耍了。

    handler机制是如何运转的?

    1.调用Looper.loop();开启循环,消息机制开始运转

     new Thread(new Runnable() {
    
                @Override
                public void run() {
                    Looper.prepare();
                    mHandler = new Handler(){
                        @Override
                        public void handleMessage(@NonNull Message msg) {
    //                        super.handleMessage(msg);
                            if (msg.what ==1){
                                Toast.makeText(MainActivity.this,msg.obj.toString(),Toast.LENGTH_SHORT).show();
                            }
                        }
                    };
                    Looper.loop();
                }
            }).start();
    
    1. 发送一条消息到消息队列
            Message message = Message.obtain();
            message.what = 1;
            message.obj = "haha";
            mHandler.sendMessage(message);
    
    1. 消息流转过程如图:
    sequenceDiagram
    Handler->>Handler: sendMessage发送消息
    Handler ->> MessageQueue: 调用enqueueMessage,把消息加入到消息队列
    Looper->>MessageQueue: loop()方法循环取消息队列中的消息
    Looper->>Handler: 调用msg.target.dispatchMessage(msg)分发消息
    Handler->>Handler: handleMessage处理消息
    

    最后调用handleMessage处理消息

        /**
         * Handle system messages here.
         */
        public void dispatchMessage(@NonNull Message msg) {
            if (msg.callback != null) {
                handleCallback(msg);
            } else {
                if (mCallback != null) {
                    if (mCallback.handleMessage(msg)) {
                        return;
                    }
                }
                handleMessage(msg);
            }
        }
    

    Android 系统中的Handler是如何应用的?

    1. Android 的主线程就是ActivityThread,主线程的入口方法为main
    public static void main(String[] args) {
            Trace.traceBegin(Trace.TRACE_TAG_ACTIVITY_MANAGER, "ActivityThreadMain");
    
            // CloseGuard defaults to true and can be quite spammy.  We
            // disable it here, but selectively enable it later (via
            // StrictMode) on debug builds, but using DropBox, not logs.
            CloseGuard.setEnabled(false);
    
            Environment.initForCurrentUser();
    
            // Set the reporter for event logging in libcore
            EventLogger.setReporter(new EventLoggingReporter());
    
            // Make sure TrustedCertificateStore looks in the right place for CA certificates
            final File configDir = Environment.getUserConfigDirectory(UserHandle.myUserId());
            TrustedCertificateStore.setDefaultUserDirectory(configDir);
    
            Process.setArgV0("<pre-initialized>");
    
            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();
            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");
        }
    

    通过Looper.prepareMainLooper()来创建主线程的Looper以及MessageQueue,并通过Looper.loop();来开启主线程的消息循环。

    1. ActivityThread内部类H继承了Handler,负责处理一些系统消息。
    class H extends Handler {
            public static final int BIND_APPLICATION        = 110;
            @UnsupportedAppUsage
            public static final int EXIT_APPLICATION        = 111;
            @UnsupportedAppUsage
            public static final int RECEIVER                = 113;
            @UnsupportedAppUsage
            public static final int CREATE_SERVICE          = 114;
            ...
      }
    

    总结

    1. MessageQueue叫消息队列,但内部实现并不是队列,是由单链表数据结构,插入和删除快。
    2. handler可以创建多个,但Looper一个线程只有一个,由sThreadLocal存储。
    private static void prepare(boolean quitAllowed) {
            if (sThreadLocal.get() != null) {
                throw new RuntimeException("Only one Looper may be created per thread");
            }
            sThreadLocal.set(new Looper(quitAllowed));
        }
    
    1. loop方法是一个死循环,只有当MessageQueue的next方法返回null,才会终止循环。当Looper的quit方法被调用时,通知消息队列退出,然后next方法返回null,才会终止循环。
    2. 当没有消息时,next方法会一直阻塞在那里,直到有新的消息来。
    3. 使用Message.obtain()来创建消息,因为内部有个对象池,能够复用,避免大量创建对象

    相关文章

      网友评论

        本文标题:Android Handler机制

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