两张图看透Android Handler使用与机制

两张图看透Android Handler使用与机制

编码文章call10242025-02-27 12:32:0718A+A-

1.Handler的使用

  • 如图所示,需要做的操作有两步:

    public class MainActivity extends AppCompatActivity {

    @Override

    protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState);

    setContentView(R.layout.activity_main); final Handler handler=new Handler(){ @Override

    public void handleMessage(Message m){ //更新ui操作

    }

    }; new Thread(){//子线程开启

    @Override

    public void run(){ Message m=new Message();

    handler.sendMessage(m);

    }

    };

    }

    }

  1. 在主线程中实例化一个Handler,并且重写HandleMessage方法用来处理子线程发送来的消息。

  2. 在子线程中,首先声明Message对象,并将Message使用主线程中实例化的Handler的sendMessage(Message)方法发送给主线程。

2.Handler的机制

  • 在使用sendMessage和handleMessage之前是有很多已经隐藏的封装好的过程的,现在一一讲解。

2.1 被消息传递的线程A准备

  • 首先要在被消息传递的线程中创建Looper,因为Handler创建的时候要绑定当前线程的Looper,使用Looper.prepare()建立。

    • Looper.prepare()

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

      }

      sThreadLocal.set(new Looper(quitAllowed));

      }private Looper(boolean quitAllowed) {

      mQueue = new MessageQueue(quitAllowed);

      mThread = Thread.currentThread();

      }

      总的来说,prepare干了两件事:创建MessageQueue和绑定当前线程。

  • 然后使用Looper.loop()让Looper开始循环访问MessageQueue。

    • Looper.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;

      ....................................... for (;;) {

      Message msg = queue.next(); // might block

      ...................................

      msg.target.dispatchMessage(msg);

      ..........................................

      msg.recycleUnchecked();// 回收Message对象

      }

      }

      总的来说,loop干了三件事:

      1.拿到当前线程的looper。

      2.根据looper拿到MessageQueue。

      3.使用for循环对MessageQueu进行无限循环询问。

      在for循环中也主要干了三件事:

      1.从消息队列中取消息,如果没有就阻塞。

      2.调用
      msg.target.dispatchMessage(msg)方法对Message进行处理。

      3.处理完成后调用msg.recycleUnchecked()回收资源。

  • 创建Handler,作为线程间通信的工具。

    public Handler(Looper looper, Callback callback, boolean async){

    mLooper = looper;

    // 与这个Handler关联的Looper中的消息队列

    mQueue = looper.mQueue;

    ...............

    }

    创建Handler时将当前线程的Looper和Looper中的MessageQueue取到。

2.2 传递消息的线程B准备

  • 创建Message时,使用Message.obtain()的效果大于New Message(),因为享元模式,维护了一个大小为50的Message对象池,比重复去创建Message更加高效。

  • Handler.sendMessage(Message)方法最终会调用sendMessageAtTime方法。

    public boolean sendMessageAtTime(Message Message, long uptimeMillis) { // 1. 获取Hndler中的消息队列

    MessageQueue queue = mQueue; if (queue == null) {

    RuntimeException e = new RuntimeException( this + " sendMessageAtTime() called with no mQueue");

    Log.w("Looper", e.getMessage(), e); return false;

    } // 2. 将要发送消息和时间入队

    return enqueueMessage(queue, Message, uptimeMillis);

    }

    总的来说,做了两件事:

    1.获取handler中的MessageQueue。

    2.调用enqueueMessage方法。

    enqueueMessage()方法代码如下:

    private boolean enqueueMessage(MessageQueue queue, Message Message, long uptimeMillis) { // 1. 将Handler赋值给Message的target

    Message.target = this; if (mAsynchronous) {

    Message.setAsynchronous(true);

    } // 2. 将Message加入到消息队列中(还有Handler)

    return queue.enqueueMessage(Message, uptimeMillis);

    }

    总的来说,做了两件事:

    1.将handler赋值给Message.target。

    2.并且将Message放入MessageQueue中。

2.3 线程间通信

  • 线程B的sendMessage流程执行完毕,至于线程A的Looper和Handler都已经创建好了,并且开始处理MessageQueue中的Message,还记得之前for循环中
    Message.target.dispatchMessage()方法吗,其实这里的Message.target就是handler,而且dispatchMessage()方法的源码如下:

    public void dispatchMessage(Message msg) {

    ..........

    handleMessage(msg);

    }

    在其中调用了handleMessage()方法,并且handleMessage()方法是个空方法,没有内容。所以我们只用重写这个方法就可以对线程B返回的消息进行处理了。

3.一些问题

  • 为什么Activity主线程没有执行Looper.prepare()和Looper.loop()?

    因为在ActivityThread的main方法中已经执行了这两个方法。

  • 一个线程可以拥有几个Looper?几个Handler?

    一个线程只能拥有一个Looper,无数个Handler。

  • 如何从主线程发送消息给子线程?

    在子线程中先建立Looper,然后再建立Handler,依靠sendMessage和handleMessage即可。

文/breakingsword(简书作者)

原文链接:
http://www.jianshu.com/p/8862ab82d0f4

点击这里复制本文地址 以上内容由文彬编程网整理呈现,请务必在转载分享时注明本文地址!如对内容有疑问,请联系我们,谢谢!
qrcode

文彬编程网 © All Rights Reserved.  蜀ICP备2024111239号-4