欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页

Android handler详解

程序员文章站 2022-03-01 13:12:56
...

一、Looper
looper是关联message与handler的重要部分。

你在Android的子线程中new handler为啥报错,和looper关系不浅,据如下个例子,在子线程中调用handler

new Thread(new Runnable() {  
            public void run() {  
                Looper.prepare();  
                Handler handler = new Handler(){  
                    @Override  
                    public void handleMessage(Message msg) {  
                        Toast.makeText(getApplicationContext(), "handler msg", Toast.LENGTH_LONG).show();  
                    }  
                };  
                handler.sendEmptyMessage(1);  
                Looper.loop();  
            };  
        }).start();
或者在子线程直接使用Looper.getMainLooper();

new Thread(new Runnable() {  
            public void run() {  
                Handler handler = new Handler(Looper.getMainLooper()){ 
                    @Override  
                    public void handleMessage(Message msg) {  
                        Toast.makeText(getApplicationContext(), "handler msg", Toast.LENGTH_LONG).show();  
                    }  
                };  
                handler.sendEmptyMessage(1);  
            };  
        }).start();

Looper.getMainLooper()实际就是主线程的looper,主线程默认都会创建looper

创建looper时会创建messagequeue

注:每一个线程只能有一个looper,looper是线程持有

Looper实际上是给当前子线程建立的looper,为了能够遍历当前子线程的消息队列,

源码

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;

        // 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();

        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);
            }

            final long slowDispatchThresholdMs = me.mSlowDispatchThresholdMs;

            final long traceTag = me.mTraceTag;
            if (traceTag != 0 && Trace.isTagEnabled(traceTag)) {
                Trace.traceBegin(traceTag, msg.target.getTraceName(msg));
            }
            final long start = (slowDispatchThresholdMs == 0) ? 0 : SystemClock.uptimeMillis();
            final long end;
            try {
                msg.target.dispatchMessage(msg);
                end = (slowDispatchThresholdMs == 0) ? 0 : SystemClock.uptimeMillis();
            } finally {
                if (traceTag != 0) {
                    Trace.traceEnd(traceTag);
                }
            }
            if (slowDispatchThresholdMs > 0) {
                final long time = end - start;
                if (time > slowDispatchThresholdMs) {
                    Slog.w(TAG, "Dispatch took " + time + "ms on "
                            + Thread.currentThread().getName() + ", h=" +
                            msg.target + " cb=" + msg.callback + " msg=" + msg.what);
                }
            }

            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();
        }
    }

二、MessageQueue
MessageQueue是一个消息队列,用于存放message,looper来把其中的message发送到handlermessage

采用先进先出的方式来管理message,内部采用单链表来进行维护,插入删除比较快

三、Message
就是咱最常用的消息了,按照我上面的说法建议使用Message.obtain()来获取Message实例,应为message有个pool

源码

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();
    }
相关标签: android

上一篇: Day3&4.字符串

下一篇: day4 字符串