Android Handler那些事儿(一)——是什么,有什么用?

Handler是什么?有什么用?

Android定义的一套同进程中线程间消息传递机制
通常用来把子线程中的UI更新消息,传递给主线程更新UI;当然也可以反过来使用,只是会麻烦一些。
Handler消息机制是由一组MessageQueue、Message、Looper、Handler共同组成的。

如果说Binder/socket是android必须掌握的IPC机制,那么Handler则是必须掌握的消息机制。

子线程使用Handler例子
class LooperThread extends Thread {
    public Handler mHandler;

    public void run() {
        Looper.prepare();
        // Step 1: 创建Handler
        mHandler = new Handler() {
            public void handleMessage(Message msg) {
                //处理即将发送过来的消息
                System.out.println("thread id="+Thread.currentThread().getId());
            }
        };

        Looper.loop();
    }
}

// Step 2: 创建并启动LooperThread线程,内部包含Looper
LooperThread looperThread = new LooperThread();
looperThread.start();

// Step 3: 发送消息
looperThread.mHandler.sendEmptyMessage(10);

可以看到,在子线程中使用Handler比在主线程中使用多了Looper.prepare();和Looper.loop();的步骤。这个之后在其他文章中叙述。

拓展问题:必须是Handler吗?还有哪些方式?

首先我们来看看经常用的有哪些异步方式。

  • 1、runOnUiThread
  • 2、View.post
  • 3、AsyncTask
1、Activity.runOnUiThread(Runnable)

Activity.java

    public final void runOnUiThread(Runnable action) {
        if (Thread.currentThread() != mUiThread) {
            mHandler.post(action);
        } else {
            action.run();
        }
    }

看来还是Handler,如果是主线程则马上执行Run方法,如果不是继续看Handler的代码

    public final boolean post(@NonNull Runnable r) {
       return  sendMessageDelayed(getPostMessage(r), 0);
    }
    
    public final boolean postDelayed(@NonNull Runnable r, long delayMillis) {
        return sendMessageDelayed(getPostMessage(r), delayMillis);
    }    

postDelayed我们经常用,和post都是调用的sendMessageDelayed方法,只是延时为0而已

    public final boolean sendMessageDelayed(@NonNull Message msg, long delayMillis) {
        if (delayMillis < 0) {
            delayMillis = 0;
        }
        return sendMessageAtTime(msg, SystemClock.uptimeMillis() + delayMillis);
    }
    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) {
        msg.target = this;
        msg.workSourceUid = ThreadLocalWorkSource.getUid();

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

注意SystemClock.uptimeMillis()是开机到现在的时间
enqueue就是入队嘛

    public Handler(@Nullable Callback callback, boolean async) {
        if (FIND_POTENTIAL_LEAKS) {
            final Class 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 " + Thread.currentThread()
                        + " that has not called Looper.prepare()");
        }
        mQueue = mLooper.mQueue;
        mCallback = callback;
        mAsynchronous = async;
    }

注意这个mQueue成员变量是在Handler构造函数中初始化的,从Looper来的

2、View.post(Runnable)

View.java

    public boolean post(Runnable action) {
        final AttachInfo attachInfo = mAttachInfo;
        if (attachInfo != null) {
            return attachInfo.mHandler.post(action);
        }

        // Postpone the runnable until we know on which thread it needs to run.
        // Assume that the runnable will be successfully placed after attach.
        getRunQueue().post(action);
        return true;
    }
    public boolean postDelayed(Runnable action, long delayMillis) {
        final AttachInfo attachInfo = mAttachInfo;
        if (attachInfo != null) {
            return attachInfo.mHandler.postDelayed(action, delayMillis);
        }

        // Postpone the runnable until we know on which thread it needs to run.
        // Assume that the runnable will be successfully placed after attach.
        getRunQueue().postDelayed(action, delayMillis);
        return true;
    }    

可以看到View的post和postDelayed的方法都是走的一样的路子,也看到了Handler的出现,但是第二条路 简单地说一下吧,细节不在这儿一一贴出了。我们使用 View.post() 时,其实内部它自己分了两种情况处理,当 View 还没有 attachedToWindow 时,通过 View.post(Runnable) 传进来的 Runnable 操作都先被缓存在 HandlerActionQueue,然后等 View 的 dispatchAttachedToWindow() 被调用时,就通过 mAttachInfo.mHandler 来执行这些被缓存起来的 Runnable 操作。从这以后到 View 被 detachedFromWindow 这段期间,如果再次调用 View.post(Runnable) 的话,那么这些 Runnable 不用再缓存了,而是直接交给 mAttachInfo.mHanlder 来执行。

3、AsyncTask

AsyncTask是一个轻量级的异步实现,可以轻松实现工作线程和UI线程的通信
他实现的原理也是 线程池 + Handler 具体怎么实现的去找源码吧

总结

到这儿我们发现好像这些异步类\方法只要涉及到了与主线程做通信,都使用了Handler,这就可以回答刚才的拓展问题了,他是Android设计之初就封装的一套消息传递机制,不用它还真不行。

你可能感兴趣的:(Android,ROM)