Handler,Message,MessageQuene三者不得不说的故事

Android开发中,Handler用的非常多,因为它和AsyncTask一样是系统提供给我们的异步的通信机制。能够将一些更新和别的不适合放在UI主线程的操作放到它们中去。

Handler的作用主要有两个:一是在线程中发送消息, 二是获取和处理消息。既可以发送消息sendEmptyMessage(int what) ,也可以发送指定的消息sendMessage(Message msg),还可以利用msg.obj的属性去传递我们需要的参数甚至对象,使原本的通信机制更为强大。


Handler发送消息的机制

Handler的出现,解决了在非UI主线程更新UI组件数据的问题。如上面提到的,我们使用handler.sendEmptyMessage(int what)  或者 sendMessage(Message msg)去发送消息,这个消息就会放去消息队列MessageQueue中,MessageQueue是个先进先出的队列,Handler按照这个顺序一直从消息队列MessageQueue中获取消息Message,并且按照约定的方式去处理这些消息。下面是最简单的发送空消息给handler去进行处理:

[java]  view plain  copy
  1. private Handler handler = new Handler(){  
  2.         @Override  
  3.         public void handleMessage(Message msg)  
  4.         {  
  5.             if(msg.what == 0x101)  
  6.             {   //约定如何处理不同的msg消息  
  7.                 Log.i("print handler message""msg.what = 0x101");  
  8.             }  
  9.             else if(msg.what == 0x201)  
  10.             {  
  11.                 Log.i("print handler message""msg.what = 0x201");               
  12.             }  
  13.         }  
  14.     };  
  15.       
  16.     /** 
  17.      * 发送空消息 
  18.      */  
  19.     private void sendMessageA()  
  20.     {  
  21.         handler.sendEmptyMessage(0x101);  
  22.     }  
  23.       
  24.     private void sendMessageB()  
  25.     {  
  26.         handler.sendEmptyMessage(0x201);  
  27.     }  
使用Handler的过程中,想必大家都会发现,如果在UI主线程中直接使用Handler去发送消息是没问题的,但放在非主线程中就会报错了。为什么呢?


Loop和MessageQueue的关系

这是因为非主线程中并不会自动创建Looper对象。Looper是顾名思义,是一个“圈”,负责管理消息队列MessgeQueue。Looper会不断(一直循环到队列中不再有message为止)从MessageQueue中读取消息并交给Handler去处理。因为我们在主线程中handler发送消息,主线程是自动帮我们初始化创建一个Looper对象的,而且每个线程只能有一个Looper。因为当然不允许同时有2个或以上的Looper对消息队列读取消息,这样就会导致类似“锁”的问题。也就是说,非UI主线程中,是不会自动帮我们创建这个Looper的。所以解决方法就是在发送消息前,先创建一个( prepare() ),然后开启它( loop() )。这样它才能正常的从消息队列中读取管理消息。


还是用上面的例子,不过改成在子线程中去创建Handler并且处理。

[java]  view plain  copy
  1. {  
  2.         private Handler mHandler;  
  3.           
  4.         @Override  
  5.         public void run() {  
  6.             // 创建Looper  
  7.             Looper.prepare();  
  8.             mHandler = new Handler(){  
  9.                 @Override  
  10.                 public void handleMessage(Message msg)  
  11.                 {  
  12.                     if(msg.what == 0x101)  
  13.                     {   //约定如何处理不同的msg消息  
  14.                         Log.i("print handler message""msg.what = 0x101");  
  15.                     }  
  16.                     else if(msg.what == 0x201)  
  17.                     {  
  18.                         Log.i("print handler message""msg.what = 0x201");               
  19.                     }  
  20.                 }  
  21.             };  
  22.             //启动Looper,这样它才能从消息队列中读取管理消息  
  23.             Looper.loop();  
  24.         }  
  25.     }  
  26.       
  27.     private void sendMessgeInThread()  
  28.     {  
  29.         MessageThread mThread = new MessageThread();  
  30.         //创建Handler  
  31.         mThread.start();  
  32.         mThread.mHandler.sendEmptyMessage(0x101);  
  33.     }  

总结三者的关系

从上面分个的来说明,我们已经知道Handler,Looper和MessageQueue分别的作用是什么。这里就总结下它们三者的关系:

情况一,在主线程中

创建Handler  ---->  使用handler发送消息  --->  消息被放入消息队列MessageQueue中  ---->  (主线程自动创建的)Looper负责不断地从消息队列中取出消息,交给Handler --->  Handler再次对不同的消息进行处理  --->  消息message被处理完后,随即被扔弃毁掉,然后继续处理第二条到达的消息message,直到Looper已经将所有消息都读取完。


情况二,在非主线程中

在上面的基础上分别调用Looper.prepare() 和 Looper.loop()方法去创建和启动Looer。创建Handler前调用Looper.prepare() ,创建完毕使用Looper.loop()。 剩下的收发消息和处理消息的过程和情况一是一样的。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值