Handler源码分析

    相信很多同学都使用过Handler,他是安卓提供的跨线程通信方案,一般是在子线程发送消息,主线程处理消息更新ui。现在我们来分析一下Handler是怎么工作的。

  • 本文涉及几个重要的对象:

Handler

    负责发送消息,处理消息。

Lopper

   负责循环从MessageQueue中取出消息,回调给Handler处理。

MessageQueue

   是一个队列,先进先出,Handler发送的消息由他存储。

Message

   消息对象。

ThreadLocal

    Android源码中: static final ThreadLocal<Looper> sThreadLocal = new ThreadLocal<Looper>(),用来存储Looper。

ThreadLocal是一个线程内部的存储类,可以用来存储数据,存储的数据只有这个线程可以访问。

  • Handler一般用法

主线程创建Handler

 Handler mainHandler = new Handler() {
        @Override
        public void handleMessage(Message msg) {
            super.handleMessage(msg);
            switch (msg.what) {
                case 1:
                    Log.e(TAG, msg.arg1 + "");
                    break;
                default:
                    break;
            }
        }
    };

子线程发送消息

new Thread(new Runnable() {
     @Override
     public void run() {
         //可以做一些耗时操作,代码省略
         //发送消息
         Message msg = new Message();
         msg.what = 1;
         msg.arg1 = 999;
         mainHandler.sendMessage(msg);
     }
}).start();

查看Handler的构造方法

    public Handler() {
        this(null, false);
    }

  public Handler(Callback callback, boolean async) {

        //省略一些代码
        ...
        //获取Looper对象,绑定到Handler
        mLooper = Looper.myLooper();
        if (mLooper == null) {
            throw new RuntimeException(
                "Can't create handler inside thread " + Thread.currentThread()
                        + " that has not called Looper.prepare()");
        }
        //获取MessageQueue对象,绑定到Handler
        mQueue = mLooper.mQueue;
        //Callback赋值
        mCallback = callback;
        mAsynchronous = async;
    }

以上代码主要做了三件事情:

1.通过Looper.myLooper()方法获取Looper对象,我们看到如果Looper.myLooper()方法返回为空的话就会报错,所以在使用Handler之前必须要先初始化Looper。

2.获取MessageQueue对象。

3.Callback赋值。

  • 分析Looper的初始化

      我们接着看Looper类里的Looper.myLooper()方法,发现Looper类中有一个成员变量 static final ThreadLocal<Looper> sThreadLocal = new ThreadLocal<Looper>(),Looper就是是存储在sThreadLocal里的。

public static @Nullable Looper myLooper() {
     return sThreadLocal.get();
}

      我们搜索整个Looper类,发现sThreadLocal只有一处存储操作,在一个私有方法prepare(boolean quitAllowed)方法中,再看Looper的构造方法,创建了一个MessageQueue。

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

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

    再搜索整个类发现有两处调用prepare(boolean quitAllowed),所以外部必须通过以下两个方法来初始化Looper

public static void prepareMainLooper() {
        prepare(false);
        synchronized (Looper.class) {
            if (sMainLooper != null) {
                throw new IllegalStateException("The main Looper has already been prepared.");
            }
            sMainLooper = myLooper();
        }
}
public static void prepare() {
        prepare(true);
}

    但是平时工作中我们在主线程创建Handler并没有调用这两个方法,当我试着在主线程中主动调用prepareMainLooper()方法的时候发现app会崩溃,报错如下:

java.lang.RuntimeException: Only one Looper may be created per thread
        at android.os.Looper.prepare(Looper.java:90)
        at android.os.Looper.prepareMainLooper(Looper.java:117)

     从报错中可以看出主线程已经初始化了Looper,不允许做二次初始化,所以我猜测主线程中的Looper初始化是Android系统源码中做的。我们都知道Activity的初始化是由ActivityThread完成的,所以猜测Looper的初始化是不是也在那呢?然后我们在AndroidSdk中搜索发现,有三个类调用了prepareMainLooper()方法:ActivityThread  SystemServer  Bridge;果然不出所料发现ActivityThread类。我们找到调用位置。

 public static void main(String[] args) {
        //省略一下代码
        ...
        //初始化Looper
        Looper.prepareMainLooper();

        //省略一下代码
        ...
        //开始循环从MessageQueue取消息
        Looper.loop();

        throw new RuntimeException("Main thread loop unexpectedly exited");
    }

发现在ActivityThread类的main()方法中调用了prepareMainLooper()对创建了主线程的Looper,然后调用了Looper.loop()方法,我们接着看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;
        //省略一些代码
        ...

        for (;;) {
            Message msg = queue.next(); // might block
            if (msg == null) {
                // No message indicates that the message queue is quitting.
                return;
            }

            //省略一些代码
            ...
            try {
                //消息分发
                msg.target.dispatchMessage(msg);
               ...
            } finally {
                ...
            }
            ...
        }
    }


//MessageQueue 类里的next方法
Message next() {

        //省略一些代码
        ...
        int nextPollTimeoutMillis = 0;
        for (;;) {
            if (nextPollTimeoutMillis != 0) {
                Binder.flushPendingCommands();
            }

            //native方法,如果nextPollTimeoutMillis为-1的时候就处于阻塞状态
            nativePollOnce(ptr, nextPollTimeoutMillis);

            synchronized (this) {
                // Try to retrieve the next message.  Return if found.
                final long now = SystemClock.uptimeMillis();
                Message prevMsg = null;
                Message msg = mMessages;
                //省略一些代码
                ...
                if (msg != null) {
                    if (now < msg.when) {
                        // Next message is not ready.  Set a timeout to wake up when it is ready.
                        nextPollTimeoutMillis = (int) Math.min(msg.when - now, Integer.MAX_VALUE);
                    } else {
                       //省略一些代码
                        ...
                        return msg;
                    }
                } else {
                    // msg为空nextPollTimeoutMillis置为-1,下次循环阻塞状态
                    nextPollTimeoutMillis = -1;
                }
                ...
            }
            ...
        }
    }
  • 分析消息的分发

loop方法里有一个死循环,不断的从MessageQueue中取出消息,并调用msg.target.dispatchMessage(msg)方法。我们到Message类中发现msg.target是个Handler对象,紧接着我们去看Handler.dispatchMessage(msg)方法

public void dispatchMessage(Message msg) {
        if (msg.callback != null) {
            handleCallback(msg);
        } else {
            if (mCallback != null) {
                if (mCallback.handleMessage(msg)) {
                    return;
                }
            }
            handleMessage(msg);
        }
}

    三种情况:

  • 1.Message.callback(Message.callback是Runnable对象)不为空。

调用handleCallback(msg)方法。

方法中回调了Runnable对象的run()方法,我们知道直接调用run()方法并没有新开启线程,而是运行在当前线程中的,也就是说是在调用Looper.loop()方法的线程中。

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

我们再接着找callback什么时候赋值的发现有两处可以由外部给callback赋值,但setCallback(Runnable r)方法是隐藏的外部无法调用所以我们只有使用obtain(Handler h, Runnable callback)方法可以给callback赋值。

public static Message obtain(Handler h, Runnable callback) {
        Message m = obtain();
        m.target = h;
        m.callback = callback;

        return m;
}

...

/** @hide */
public Message setCallback(Runnable r) {
        callback = r;
        return this;
}

所以Handler的用法还有这样一种:

private Handler handler = new Handler();

...

private void sendMsg(){
        Message msg = Message.obtain(handler, new Runnable() {
            @Override
            public void run() {
                Log.e(TAG, "Thread  "+Thread.currentThread().getName());
            }
        });
        msg.what = 0;

        handler.sendMessage(msg);
}


....

//调用代码
new Thread(new Runnable() {
    @Override
    public void run() {
        sendMsg();
    }
}).start();

运行结果:Thread  main

虽然我们是在子线程里发送的消息,但是Runnable中的run()方法中却是主线程:因为我们是在主线程创建的Handler,主线程的Handler在ActivityThread类的main方法中初始化了Looper,并调用了Looper.loop()方法,所以回调到callback的run()方法是在主线程,这样就实现了子线程与主线程通信。简单来说Looper.loop()运行在哪个线程,所以callback的run()方法就运行在哪个线程。

  • 2.Message.callback为空且Handler.mCallback(Handler.mCallback是一个接口)不为空

调用mCallback.handleMessage(msg)方法。

我们查看Handler类发现,外部给mCallback的赋值可以通过调用以下几个方法:

public Handler(Callback callback) {
        this(callback, false);
}

 public Handler(Looper looper, Callback callback) {
        this(looper, callback, false);
}

public static Handler createAsync(@NonNull Looper looper, @NonNull Callback callback) {
        if (looper == null) throw new NullPointerException("looper must not be null");
        if (callback == null) throw new NullPointerException("callback must not be null");
        return new Handler(looper, callback, true);
}

所以Handler还有以下用法

private Handler handler = new Handler(new Handler.Callback() {
        @Override
        public boolean handleMessage(Message msg) {
            Log.e(TAG, "Thread  "+Thread.currentThread().getName());
            return false;
        }
});

private void sendMsg2(){
        Message msg = Message.obtain();
        handler.sendMessage(msg);
}


//调用代码
new Thread(new Runnable() {
     @Override
     public void run() {
          sendMsg2();
     }
}).start();

运行结果:Thread  main

注意:我们发现mCallback.handleMessage(msg)有个boolean类型返回值,如果返回true,那么就不再调用Handler自己的handleMessage(msg)。

  • 3.Message.callback为空且Handler.mCallback为空

调用Handler.handleMessage(msg)方法。

这种用法就是文中开头的最常见是的用法,回调我们再主线程创建的Handler重写的handleMessage(msg)方法。

至此Handler源码的主流程分析完毕

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值