职业IT人-IT人生活圈

 找回密码
 成为会员
搜索
查看: 421|回复: 1

android中Handler,Looper,Message的疑问

[复制链接]
楠楠 发表于 2011-8-13 10:43 | 显示全部楼层 |阅读模式
  
最近做的项目中涉及到线程间通信,我先把我的项目说下:

    Activity启动后点击一个界面按钮后会开启一个服务(暂定为padService),在padService中会启动一个线程(暂定为Thread-3)发起Socket连接。我们项目中使用mina作为socket通信框架,用过mina的同志们应该熟悉,Thread-3只是负责监听,具体的消息处理是另外的线程。在我们的IoHandler中处理消息,现在的问题是,我需要在IoHander的sessionOpened方法中给Activity一个消息去更新UI界面,这个就涉及到不同线程间的通信了。

   网上搜索后,在android中线程间通信使用Handler,Looper,Message这几个对象(不熟悉这些概念的同志们请自己查下)。
   这是网上的一个使用例子:

Java代码  
<SPAN style="FONT-SIZE: medium">public class Activity2 extends Activity implements OnClickListener{   
  
       Button button = null;   
  
       TextView text = null;   
  
       MyHandler mHandler = null;   
  
       Thread thread ;   
  
       @Override  
  
       protected void onCreate(Bundle savedInstanceState) {   
  
              super.onCreate(savedInstanceState);   
  
              setContentView(R.layout.activity1);            
  
              button = (Button)findViewById(R.id.btn);   
  
              button.setOnClickListener(this);   
  
              text = (TextView)findViewById(R.id.content);   
  
       }   
  
       public void onClick(View v) {   
  
              switch (v.getId()) {   
  
              case R.id.btn:   
  
                     thread = new MyThread();   
  
                     thread.start();   
  
                     break;   
  
              }               
  
       }         
  
       private class MyHandler extends Handler{                 
  
              public MyHandler(Looper looper){   
  
                     super(looper);   
  
              }   
  
              @Override  
  
              public void handleMessage(Message msg) {//处理消息   
  
                     text.setText(msg.obj.toString());   
  
              }               
  
       }   
  
       private class MyThread extends Thread{   
  
              @Override  
  
              public void run() {   
  
                     Looper curLooper = Looper.myLooper();   
  
                     Looper mainLooper = Looper.getMainLooper();   
  
                     String msg ;   
  
                     if(curLooper==null){   
  
                            mHandler = new MyHandler(mainLooper);   
  
                            msg = "curLooper is null";   
  
                     }else{   
  
                            mHandler = new MyHandler(curLooper);   
  
                            msg = "This is curLooper";   
  
                     }   
  
                     mHandler.removeMessages(0);   
  
                     Message m = mHandler.obtainMessage(1, 1, 1, msg);   
  
                     mHandler.sendMessage(m);   
  
              }               
  
       }   
  
}</SPAN>  

public class Activity2 extends Activity implements OnClickListener{

       Button button = null;

       TextView text = null;

       MyHandler mHandler = null;

       Thread thread ;

       @Override

       protected void onCreate(Bundle savedInstanceState) {

              super.onCreate(savedInstanceState);

              setContentView(R.layout.activity1);         

              button = (Button)findViewById(R.id.btn);

              button.setOnClickListener(this);

              text = (TextView)findViewById(R.id.content);

       }

       public void onClick(View v) {

              switch (v.getId()) {

              case R.id.btn:

                     thread = new MyThread();

                     thread.start();

                     break;

              }            

       }      

       private class MyHandler extends Handler{              

              public MyHandler(Looper looper){

                     super(looper);

              }

              @Override

              public void handleMessage(Message msg) {//处理消息

                     text.setText(msg.obj.toString());

              }            

       }

       private class MyThread extends Thread{

              @Override

              public void run() {

                     Looper curLooper = Looper.myLooper();

                     Looper mainLooper = Looper.getMainLooper();

                     String msg ;

                     if(curLooper==null){

                            mHandler = new MyHandler(mainLooper);

                            msg = "curLooper is null";

                     }else{

                            mHandler = new MyHandler(curLooper);

                            msg = "This is curLooper";

                     }

                     mHandler.removeMessages(0);

                     Message m = mHandler.obtainMessage(1, 1, 1, msg);

                     mHandler.sendMessage(m);

              }            

       }

}

这个没有问题,基本上三个对象的使用也很清楚,myHandler虽然是由子线程new出来的,但主线程持有引用,在我们的项目中不能用,因为我们几个线程属于不同的类,我尝试用下面的方法解决:

    在IoHandler中new一个android的handler,参数为主线程的Looper:


Java代码  
<SPAN style="FONT-SIZE: medium">new Handler(Looper.getMainLooper()).sendMessage(msg);</SPAN>  

new Handler(Looper.getMainLooper()).sendMessage(msg);IoHandler所在的线程给主线程发送消息(looper是主线程的,消息也就放在主线程的消息队列里了)
但是在主线程的handleMessage方法中得不到消息,尝试失败。

    那么怎么办呢,让IoHandler持有主线程的handler引用,具体做法有两种方式:
    1.  参数传递,把主线程的handler通过参数传递的形式传到IoHandler中。
    2. 静态变量,把主线程的handler申明为公共静态变量

Java代码  
<SPAN style="FONT-SIZE: medium">public static Handler mainHandler;</SPAN>  

public static Handler mainHandler; 这样在Iohandler中使用

Java代码  
<SPAN style="FONT-SIZE: medium">welcomeActivity.mainHandler.sendMessage(msg);</SPAN>  

welcomeActivity.mainHandler.sendMessage(msg); 这两种方式在主线程的  handleMessage的方法中都可以得到IoHandler发送的消息。
本人使用的是静态变量解决的,因为有好几个来实现通信,参数传递太麻烦。

那为什么我的第一种尝试是失败的呢,我是把消息放到主线程的消息队列了啊,这就要看android的一些实现机制了。
通过网络和android的api,本人的理解如下:
Looper是MessageQueue和Handler沟通的桥梁,Handler通过Looper把消息放入消息队列(MessageQueue),你想把消息发给谁,就把谁的looper作为参数传给Handler

Java代码  
<SPAN style="FONT-SIZE: medium">newHandler(Looper looper);</SPAN>  

newHandler(Looper looper);  Looper把消息放入消息队列,并广播消息,这个不太好理解,我举例如下:

   主线程的Handler我们这样定义:Handler mainHandler = new Handler();  如果Handler没有参数,默认为当前线程的Looper
   子线程的Handler我们这样定义: Handler subHandler = newHandler(Looper.getMainLooper()); 参数为主线程的Looper
这样两个线程都会把消息放入主线程的消息队列里了。
   现在mainHandler.sendMessage(), 消息进入主线程的消息队列,Looper广播消息,其实就是调用mainHandler的dispatchMessage方法,所有持有mianHandler引用的类都可以收到消息,注意啊,现在subHandler并不能接受到消息,因为Looper并没有调用subHandler的dispatchMessage方法,所以应该这样理解广播,A发送消息,那么A的Looper就调用A的dispatchMessage方法,别的B,C, D虽然也是A的Looper,但没有A的引用,所以B,C,D是接受不到消息的,如果B, C,D持有A的引用,但B,C,D不用A的Looper,那么也是接受不到消息的。这点在开发时要特别注意。

  以上是我在使用Looper, Handler ,Message中的一些问题,可能有理解错的地方,请大大们指出来。
  我的疑惑是难道子线程必须持有主线程的引用才可以给主线程发送消息吗?要知道我们的子线程并不一定和主线程一个类,可能在别的类中,这个引用传递实在太麻烦了,期望有更好的解决方式。

爱车车 发表于 2011-8-13 10:43 | 显示全部楼层
推荐链接

见证又一个准百万富翁的诞生!
3G培训就业月薪平均7K+,不3K就业不花一分钱!
20-30万急聘多名天才Java/MTA软件工程师

您需要登录后才可以回帖 登录 | 成为会员

本版积分规则

QQ|手机版|小黑屋|网站帮助|职业IT人-IT人生活圈 ( 粤ICP备12053935号-1 )|网站地图
本站文章版权归原发布者及原出处所有。内容为作者个人观点,并不代表本站赞同其观点和对其真实性负责,本站只提供参考并不构成任何投资及应用建议。本站是信息平台,网站上部分文章为转载,并不用于任何商业目的,我们已经尽可能的对作者和来源进行了通告,但是能力有限或疏忽造成漏登,请及时联系我们,我们将根据著作权人的要求立即更正或者删除有关内容。

GMT+8, 2024-5-2 12:34 , Processed in 0.123528 second(s), 20 queries , Gzip On.

Powered by Discuz! X3.4

Copyright © 2001-2021, Tencent Cloud.

快速回复 返回顶部 返回列表