Handler Looper MessageQueue Thread HandlerThread IntentService 的简单解析

Handler Looper MessageQueue Thread HandlerThread IntentService 的简单解析

这几个类应该是Android 很基础也很重要的几个类了。可以用这几个类做很多有意思的东西,
比如

Handler 类解析

Handler 一般作为消息的接收者的角色,接收某个线程发出的 Message 并处理。那 Handler 是如何接收以及如何处理 Message 的呢?我们先看下该类的构造方法。

public Handler() { // 构造方法 1
    this(null, false);
}

public Handler(Callback callback, boolean async) { // 构造方法 2
    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());
        }
    }

    mLooper = Looper.myLooper();
    if (mLooper == null) {
        throw new RuntimeException(
            "Can't create handler inside thread that has not called Looper.prepare()");
    }
    mQueue = mLooper.mQueue;
    mCallback = callback;
    mAsynchronous = async;
}

我们一般都是通过 new Handler() 这样的方式来创建一个 Handler , 通过上面的构造方法,我们可以得知,这种方式最终调用了构造方法 2 来构造一个 Handler ,而构造方法 2 里面最终执行了以下的关键代码。

    // 获取和当前线程绑定的 Looper
    mLooper = Looper.myLooper();
    if (mLooper == null) {
        throw new RuntimeException(
            "Can't create handler inside thread that has not called Looper.prepare()");
    }
    // 拿到当前线程 looper 的 mQueue
    mQueue = mLooper.mQueue;
    // 持有回调方法,回调方法会在 dispatchMessage 方法里面用到
    mCallback = callback;
    mAsynchronous = async;

查看 Handler 的源码,你会发现还有一个构造方法

public Handler(Looper looper, Callback callback, boolean async) {
    mLooper = looper;
    mQueue = looper.mQueue;
    mCallback = callback;
    mAsynchronous = async;
}

从这个构造方法来看,直接是给 mLoopermCalbackmAsynchronous 赋值。看着似乎和上面的 2 个构造方法没有特别多的区别,仔细想想区别还是蛮大,最大个一个区别应该是对 mLooper 赋值了,前 2 个构造方法没法直接指定 mLooper 绑定的线程,在哪个线程初始化的,mLooper 就是哪个线程绑定的 Looper , 而最后的一个构造方法是可以指定 mLooper 的,即你可以随意指定一个线程的 Looper , 包括 UI 线程的。

Handler 构造完成后,我们一般是发送消息,然后接收到消息后处理消息,我们先看看 Handler 里我们常用的发送消息的方法

public final boolean post(Runnable r) {
    return  sendMessageDelayed(getPostMessage(r), 0);
}

private static Message getPostMessage(Runnable r) {
    Message m = Message.obtain();
    m.callback = r;
    return m;
}

public final boolean sendMessageDelayed(Message msg, long delayMillis) {
    if (delayMillis < 0) {
        delayMillis = 0;
    }
    return sendMessageAtTime(msg, SystemClock.uptimeMillis() + delayMillis);
}

public boolean sendMessageAtTime(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(MessageQueue queue, Message msg, long uptimeMillis) {
    msg.target = this;
    if (mAsynchronous) {
        msg.setAsynchronous(true);
    }
    return queue.enqueueMessage(msg, uptimeMillis);
}

从上面的代码可以看到,大概的一个流程是这样的,首先是创建了一个 Message ,这个 Message 携带了一些信息, whatobjcallback 等。这个 Message 最终被添加到了这个 Handler 的 mQueue 里面。而这个 mQueuemLooper 来负责管理的。所以 Message 发出去后,后面是如何运行的,我们需要去查阅 Looper 的代码了。

Looper 类解析

Looper 这个类的内容并不多,我们还是从构造方法入手来看

    private Looper(boolean quitAllowed) {
        mQueue = new MessageQueue(quitAllowed);
        mThread = Thread.currentThread();
    }

可以看到,是一个私有的构造方法,所以一般我们不能通过 new 的方式来创建一个 Looper 对象。既然无法直接 new 一个对象,那肯定会有其他方式可以获取一个 Looper ,要不然我们如何拿到 Looper 呢。再次查阅源码我们发现下面的代码


    /**
     * Returns the application's main looper, which lives in the main thread of the application.
     */
    public static Looper getMainLooper() {
        synchronized (Looper.class) {
            return sMainLooper;
        }
    }

    /**
     * Return the Looper object associated with the current thread.  Returns
     * null if the calling thread is not associated with a Looper.
     */
    public static @Nullable Looper myLooper() {
        return sThreadLocal.get();
    }

只有这2个方法可以获取到一个 Looper ,从代码里面看到,基本都是返回某个对象,还是没看到 new Looper 类似的代码,继续看代码我们发现了下面的几个方法

    /** Initialize the current thread as a looper.
      * This gives you a chance to create handlers that then reference
      * this looper, before actually starting the loop. Be sure to call
      * {@link #loop()} after calling this method, and end it by calling
      * {@link #quit()}.
      */
    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");
        }
        // new 了一个 Looper 并和当前线程绑定
        sThreadLocal.set(new Looper(quitAllowed));
    }

    /**
     * Initialize the current thread as a looper, marking it as an
     * application's main looper. The main looper for your application
     * is created by the Android environment, so you should never need
     * to call this function yourself.  See also: {@link #prepare()}
     */
    public static void prepareMainLooper() {
        prepare(false);
        synchronized (Looper.class) {
            if (sMainLooper != null) {
                throw new IllegalStateException("The main Looper has already been prepared.");
            }
            sMainLooper = myLooper();
        }
    }

可以看到这几个方法大概的意思是如果当前线程没有绑定 Looper,那么就新建一个 Looper 和当前线程绑定。

Looper 类里面的代码差不多都介绍了,还剩下最关键的一个方法,就是下面的方法。

    /**
     * Run the message queue in this thread. Be sure to call
     * {@link #quit()} to end the loop.
     */
    public static void loop() {
        // 获取当前线程的 Looper 
        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();

        // 一个死循环,不停从 queue 里面拿出 Message,然后处理
        // 如果没有 Message 了,就等待
        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
            Printer logging = me.mLogging;
            if (logging != null) {
                logging.println(">>>>> Dispatching to " + msg.target + " " +
                        msg.callback + ": " + msg.what);
            }

            msg.target.dispatchMessage(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();
        }
    }

通过代码可以看到,这个方法的主要做了一件事,就是不停从 queue 里面拿出 Message ,然后处理,如果没有 Message 了,就等待。

单独看 Looper 的源码,好像并不是特别的清晰,我们找个场景串一下,更好理解。我们看下 App 的启动,在 ActivityThread 这个类里面有个 main 方法,这个方法可以只关注下面的2行代码

    public static void main(String[] args) {
        ...
        Looper.prepareMainLooper();
        ...
        Looper.loop();
    }

从代码可以看到先是调用了 Looper.prepareMainLooper() 方法将 UI 线程和 Looper 绑定,接着调用了 Looper.loop() 方法从当前线程绑定的 Looper 的 mQueue 里面拿消息处理。这也告诉我们,如果需要在一个线程里面使用 Handler,需要先调用 Looper.prepare() 方法,接着调用 Looper.loop() ,才可以使用 Handler。

Looper.loop() 方法里面有一行代码很关键

msg.target.dispatchMessage(msg);

这行代码的意思是,取到 msg 的时候会交给 msgtargetdispatchMessage 这个 msg。从前面的 enqueueMessage 方法我们得知 Messagetarget 正是发送 MessageHandler。那我们看看 HandlerdispatchMessage 方法。

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

private static void handleCallback(Message message) {
    message.callback.run();
}

这段代码告诉我们,会先去看看 Messagecallback 是否为空,如果不为空,交给 callback 处理。如果为空,那么再去看看 HandlermCallback 是否为空,不为空交个 mCallback 处理,如果为空的话,就交个 HandlerhandlerMessage 方法去处理,这个方法大家应该比较熟悉了。

从前面的 post 调用分析,我们知道 msg.callback 其实就是那个 postRunnablle,所以 postrunnable 最终会在当前线程绑定的 looper 从消息队列中取到消息的时候去处理。而处理的线程就是 这个 looper 所在的线程里,如果这个 looper 是主线程,那么就不能做耗时操作。

Handler 还有一个常用的方法是

public final boolean sendMessage(Message msg) {
    return sendMessageDelayed(msg, 0);
}

public final boolean sendMessageDelayed(Message msg, long delayMillis) {
    if (delayMillis < 0) {
        delayMillis = 0;
    }
    return sendMessageAtTime(msg, SystemClock.uptimeMillis() + delayMillis);
}

看下来其实和 post 方法并没有太大区别,只是 Message 是我们自己创建的,不一定会设置 callback 值,如果设置了 callback 的值,调用的顺序和 post 一致了。

到这里, Handler 和 Looper 的解析大概就完成了。先调用 Looper 的 prepare() 方法和 loop() 方法,让 Looper 的框架跑起来,不停从 mQueue 里面取消息处理。然后是新建一个 Handler 和 Looper 绑定,方便后续发送消息到 Looper 的 mQueue 里面,消息发送到了 Looper 的 mQueue 里面后, Looper 最终会取出这个消息,然后处理这个消息。

HandlerThread

这个也是一个比较特殊的类。从类名初步看是一个线程,先看看这个类的主要代码。

public class HandlerThread extends Thread {
    int mPriority;
    int mTid = -1;
    Looper mLooper;

    public HandlerThread(String name) {
        super(name);
        mPriority = Process.THREAD_PRIORITY_DEFAULT;
    }

    //··· 忽略其他代码

    @Override
    public void run() {
        mTid = Process.myTid();
        Looper.prepare();
        synchronized (this) {
            mLooper = Looper.myLooper();
            notifyAll();
        }
        Process.setThreadPriority(mPriority);
        onLooperPrepared();
        Looper.loop();
        mTid = -1;
    }

    public Looper getLooper() {
        if (!isAlive()) {
            return null;
        }

        // If the thread has been started, wait until the looper has been created.
        synchronized (this) {
            while (isAlive() && mLooper == null) {
                try {
                    wait();
                } catch (InterruptedException e) {
                }
            }
        }
        return mLooper;
    }
}

仔细观察,发现里面有一个 mLooper 属性,还有一个 getLooper 方法。结合前面的 Handler 的分析,我们在创建一个 Handler 的时候可以传入一个 Looper ,并且这个 Handler 发送的 Message 的处理是在和 Looper 绑定的线程下面的。如果我们想利用 Handler 处理耗时任务,那我们可以用 HandlerThread 来处理。

IntentService

之所以提这个类是因为用到了 HandlerThread ,而且也是一个比较有用的类,从类的名字我们可以知道,这个是一个 Service , Service 一般用于处理后台任务。

我们先简单看下源码

public abstract class IntentService extends Service {

    ...

    private final class ServiceHandler extends Handler {
        public ServiceHandler(Looper looper) {
            super(looper);
        }

        @Override
        public void handleMessage(Message msg) {
            onHandleIntent((Intent)msg.obj);
            stopSelf(msg.arg1);
        }
    }

    /**
     * Creates an IntentService.  Invoked by your subclass's constructor.
     *
     * @param name Used to name the worker thread, important only for debugging.
     */
    public IntentService(String name) {
        super();
        mName = name;
    }

    ...

    @Override
    public void onCreate() {
        // TODO: It would be nice to have an option to hold a partial wakelock
        // during processing, and to have a static startService(Context, Intent)
        // method that would launch the service & hand off a wakelock.

        super.onCreate();
        HandlerThread thread = new HandlerThread("IntentService[" + mName + "]");
        thread.start();

        mServiceLooper = thread.getLooper();
        mServiceHandler = new ServiceHandler(mServiceLooper);
    }

    @Override
    public void onStart(Intent intent, int startId) {
        Message msg = mServiceHandler.obtainMessage();
        msg.arg1 = startId;
        msg.obj = intent;
        mServiceHandler.sendMessage(msg);
    }

    ...

    /**
     * This method is invoked on the worker thread with a request to process.
     * Only one Intent is processed at a time, but the processing happens on a
     * worker thread that runs independently from other application logic.
     * So, if this code takes a long time, it will hold up other requests to
     * the same IntentService, but it will not hold up anything else.
     * When all requests have been handled, the IntentService stops itself,
     * so you should not call {@link #stopSelf}.
     *
     * @param intent The value passed to {@link
     *               android.content.Context#startService(Intent)}.
     */
    @WorkerThread
    protected abstract void onHandleIntent(Intent intent);
}

首先,IntentService 是一个抽象类,不能直接使用,子类需要实现 onHandleIntent 才可以。

然后我看启动过程,在 onCreate() 方法里面创建了一个 HandlerThread 和一个 ServiceHandler ,同时将 HandlerThreadLooperServiceHandler 绑定,我们调用 startService() 方法后,最终 onStart 方法被调用,可以看到这个这个 intent 最终交给了 ServiceHandler 的 handleMessage 方法 处理, 在 handleMessage 方法里面给了 onHandleIntent 去处理。

仔细思考,由于 Looper 处理消息是一个一个的处理,所以 IntentService 也是一个一个地处理事件,并且事件处理完后会尝试关闭,节省资源,简化代码。

阅读更多
版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/wxy318/article/details/79974748
个人分类: Android
上一篇MiniTasker 一个方便切换线程去执行耗时任务,并且可以在需要回调到 UI 线程的时候能简便切换到 UI 线程的开源库
下一篇Android 性能优化总结
想对作者说点什么? 我来说一句

没有更多推荐了,返回首页

关闭
关闭
关闭