android消息机制,异步和多线程

隐身守侯 提交于 2019-12-05 12:57:20

android消息机制,异步和多线程

前言

    在xxxx1.92正式版的时候付费购买曾单独封装了一个流程PaymentFlow并继承于Handler,调用方只要依据这个流程创建流程实例并触发开始,实例即可依据设定的支付流程完成.但在异步和多线程方面却有 java.lang.RuntimeException: Can't create handler inside thread that has not called Looper.prepare()’的问题.最近在作风网络库的替换,网络库使用的Handler的继承类MessageHandler作为回调.同样也存在多线程的异步调用或诸塞的问题,所以在此就将Handler的机制在研究一遍.

1.  Handler,Looper,Activity

Android应用程序是消息驱动的,并通过Looper,Handler来实现消息循环机制,且是针对线程的. 一个线程可以存在(当然也可以不存在)一个消息队列和一个消息循环(Looper),特定线程的消息只能分发给本线程,不能进行跨线程,跨进程通讯.但是创建的工作线程默认是没有消息循环和消息队列的,如果想让该线程具有消息队列和消息循环,需要在线程中首先调用Looper.prepare()来创建消息队列,然后调用Looper.loop()进入消息循环. Handler的作用是把消息加入特定的(Looper)消息队列中,并分发和处理该消息队列中的消息.构造Handler的时候可以指定一个Looper对象,如果不指定则利用当前线程的Looper创建.Activity是一个UI线程,运行于主线程中,Android系统在启动的时候会为Activity创建一个消息队列和消息循环(Looper.一个Activity中可以创建多个工作线程或者其他的组件,如果这些线程或者组件把他们的消息放入Activity的主线程消息队列,那么该消息就会在主线程中处理了.之间的关系如下图所示

 

我们可以写个测试用例在ActivityHandler中分别打印出线程编号就明白在默认情况下(例如: private Handler handler = new Handler();),ActivityHandler是在同个线程上运行的.

如果一个线程中调用Looper.prepare(),那么系统就会自动的为该线程建立一个消息队列,然后调用 Looper.loop();之后就进入了消息循环,这个之后就可以发消息、取消息、和处理消息.这个如何发送消息和如何处理消息可以在其他的线程中通过Handle来做,但前提是我们的Hanle知道这个子线程的Looper,但是你如果不是在子线程运行 Looper.myLooper(),一般是得不到子线程的looper.

除此也可以通过创建HandlerThread来为Handler来创建一个新得的Looper并赋予Handler,这样Handler就会在非主线程执行.

HandlerThread thread=new HandlerThread(“handler_thread”));

thread.start();

Handler m=new Handler(thread.getLooper());

2.  HandlerThread的区别

Handler与调用者处于同一线程,如果Handler里面做耗时的动作,调用者线程会阻塞.Android UI操作不是线程安全的,并且这些操作必须在UI线程中执行.Android提供了几种基本的可以在其他线程中处理UI操作的方案,包括Activity runOnUiThread(Runnable),Viewpost以及1.5版本的工具类AsyncTask等方案都采用了 Handler,Handlerpost对线程的处理也不是真正start一个新的线程,而是直接调用了线程的run方法.

 

3.  Handler对于Message的处理不是并发的

一个Looper 只有处理完一条Message才会读取下一条,所以消息的处理是阻塞形式的.但是如果用不同的Looper则能达到并发的目的.Service ,onStart的执行也是阻塞的.如果一个startServiceonStart执行完成之前,再次条用startService也会阻塞.如果希望能尽快的执行onStart则可以在onStart中使用handler,因为Messagesend是非阻塞的.如果要是不同消息的处理也是并发 ,则可以用不同的Looper实例化Handler.

 

4.  资源回收

Handler对象发送类似new Message()形式的空Message可以达到清空Message的目的,这种做法与getLooper().quit()的做法是一样的.如果利用的资源较多,应及时清理.

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!