安卓Handler,Looper消息传递机制

版权声明:转载必须注明本文转自郭子轩的博客 https://blog.csdn.net/gpf1320253667/article/details/52650045
1.Handler出现的原因:
  首先安卓高版本不允许直接在主线程中执行一些耗时操作,因为会造成ANR,影响用户体验,耗时操作包括:
  网络访问,耗时运算,阻塞式的IO,因此我们必须开启一个子线程来执行这些耗时操作,但是开启了子线程
  之后又存在另外一个问题: Android中规定子线程不能直接修改UI界面。
  因此如果子线程想要间接地修改UI界面,方式有多种,此处介绍使用安卓中的handler消息传递机制来实现。
  可以借助Handler的sendMessage(msg)方法向UI主线程发送修改界面的消息,并且可以将子线程中获得的数
  据借助于Handler传递给主线程,然后主线程接收到消息之后,调用handleMessage方法进行处理。
2.Handler的作用:
  实现子线程和UI主线程的通信,具体作用主要有两个:
  1.在子线程中使用sendMessage(msg)等方法发送消息给Looper管理的消息队列。
  2.在UI主线程中获取Lopper分给他的消息,调用handleMessage方法进行相应的处理。
3.与Handler相关的几个两个类:
  1.Looper:消息泵,每个线程只能拥有一个Looper,它的loop方法会使用死循环的方式不断地从消息队列
            MessageQueue中取出消息并将该消息交给发送该消息的Handler来处理。
  2.MessageQueue:消息队列,它采用先进先出的方式来管理队列中的所有Message,调用Looper的
            prepare()方法为当前线程创建Looper对象时,他的构造器会创建与之配套的MessageQueue。
            因此,一个MessageQueue需要一个Looper。
4.Handler的使用必须借助于Looper对象,即使用Handler时必须创建一个Looper对象。
  Looper是Handler与消息队列之间通讯的桥梁,因此必须在当前线程中存在一个Looper对象,Looper对象
  在当前线程中是否存在分以下两种情况:
  1.在UI主线程中创建Handler对象时,系统已经初始化了一个Looper对象,因此程序直接创建Handler对象即可,
    然后使用Handler对象来接收和处理消息。(前面用的都是这种方式)
  2.在自定义的线程类中要创建Handler对象时,我们必须手动的创建一个Looper对象,并且调用loop()
    方法启动它,在自定义的线程类中使用Handler的步骤如下:
    1.首先创建Looper对象 --- 调用Looper的prepare()方法来创建Looper对象
    2.创建Handler实例并重写handleMessage(msg)方法来处理消息。
    3.启动Looper --- 调用Looper的loop()方法。
  使用的代码示例如下:

  //自定义线程类

class CalThread extends Thread{
        public Handler mHandler = null;
        @Override
        public void run() {
            Looper.prepare();//创建Looper对象
            mHandler = new Handler(){
                public void handleMessage(android.os.Message msg) {
                    //执行相应的操作
                };
            };
            Looper.loop();//启动looper
        }

    }

5.Message类的创建及几个属性:

  1.Message虽然也可以通过new来获取,但是通常使用Message.obtain()或Handler.obtainMessage()方法来
    从消息池中获得空消息对象,以节省资源;
    //message 从handler 类获取,从而可以直接向该handler 对象发送消息
    Message msg = handler.obtainMessage();  
    msg.arg1 = i;  
    msg.sendToTarget();    
  2.几个属性使用介绍:
   what:int类型的消息标识
   arg1:用来存放int类型数据
   arg2:用来存放int类型数据
   obj :用来存放Object数据
   注意:
   1.如果一个Message只需要携带简单的int型数据,应优先使用arg1和arg2属性来传递数据,这样比其他
     方式节省内存;
   2.同样由于obj在传递数据时要向下转型,这样对于具体的类型就又存在安全隐患,因此我们可以考虑借助
     setData(Bundle bundle)方法来传递参数。
----------------------------------------------------------------------------------------------
6.Handler消息传递机制的过程:
  例如在子线程执行联网操作获取到网络数据时,首先创建Message消息对象msg,将获取到的数据设置到msg
  对象中,再调用Handler的sendMessage(msg)方法将该消息发送到MessageQueue消息队列中,然后该消息
  队列的管理者Looper通过调用loop()方法采用先进先出的方式不断地将队列中的消息取出并发送给发送该
  消息的Handler进行处理,handler在获取到该消息后就会调用handleMessage方法进行处理,即从该msg中
  取出携带的数据,在主线程中执行修改UI界面的操作。
----------------------------------------------------------------------------------------------
7.主要依靠以下方法来完成消息调度:
post(Runnable)、
postAtTime(Runnable, long)、
postDelayed(Runnable, long)、
sendEmptyMessage(int)、
sendMessage(Message)、
sendMessageAtTime(Message, long)、
sendMessageDelayed(Message, long)
【备注:】
1.post方法是当到Runable对象到达就被插入到消息队列;
2.sendMessage方法允许你把一个包含有信息的Message插入消息队列,它会在Handler的
  handlerMessage(Message)方法中执行(该方法要求在Handler的子类中实现)。
3.当Handler post或者send消息的时候,可以在消息队列准备好的时候立刻执行,或者指定一个延迟处理或绝
  对时间对它进行处理,后两个是实现了timeout、ticks或者其他timing-based的行为。
4.当你的应用创建一个进程时,其主线程(UI线程)会运行一个消息队列,负责管理优先级最高的应用程序
  对象(Activity、广播接收器等)和任何他们创建的windows。你也可以创建自己的线程,通过handler与
  主线程进行通信,在新创建的线程中handler通过调用post或sendMessage方法,将传入的Runnable或
  者Message插入到消息队列中,并且在适当的时候得到处理。
-------------------------------------------------------------------------------------------
备注:安卓中主线程和子线程通信的6种方式:
1.使用handler
2.调用Activity的runOnUiThread()方法
3.异步任务AsyncTask
4.View.post()
5.View.postDelayed()
6.异步装载Loader


猜你喜欢

转载自blog.csdn.net/gpf1320253667/article/details/52650045