Handler不同线程间的通信

转http://www.iteye.com/problems/69457  

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

 

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

   这是网上的一个使用例子:

 

Java代码  

  1. public class Activity2 extends Activity implements OnClickListener{  
  2.   
  3.        Button button = null;  
  4.   
  5.        TextView text = null;  
  6.   
  7.        MyHandler mHandler = null;  
  8.   
  9.        Thread thread ;  
  10.   
  11.        @Override  
  12.   
  13.        protected void onCreate(Bundle savedInstanceState) {  
  14.   
  15.               super.onCreate(savedInstanceState);  
  16.   
  17.               setContentView(R.layout.activity1);           
  18.   
  19.               button = (Button)findViewById(R.id.btn);  
  20.   
  21.               button.setOnClickListener(this);  
  22.   
  23.               text = (TextView)findViewById(R.id.content);  
  24.   
  25.        }  
  26.   
  27.        public void onClick(View v) {  
  28.   
  29.               switch (v.getId()) {  
  30.   
  31.               case R.id.btn:  
  32.   
  33.                      thread = new MyThread();  
  34.   
  35.                      thread.start();  
  36.   
  37.                      break;  
  38.   
  39.               }               
  40.   
  41.        }        
  42.   
  43.        private class MyHandler extends Handler{                
  44.   
  45.               public MyHandler(Looper looper){  
  46.   
  47.                      super(looper);  
  48.   
  49.               }  
  50.   
  51.               @Override  
  52.   
  53.               public void handleMessage(Message msg) {//处理消息  
  54.   
  55.                      text.setText(msg.obj.toString());  
  56.   
  57.               }               
  58.   
  59.        }  
  60.   
  61.        private class MyThread extends Thread{  
  62.   
  63.               @Override  
  64.   
  65.               public void run() {  
  66.   
  67.                      Looper curLooper = Looper.myLooper();  
  68.   
  69.                      Looper mainLooper = Looper.getMainLooper();  
  70.   
  71.                      String msg ;  
  72.   
  73.                      if(curLooper==null){  
  74.   
  75.                             mHandler = new MyHandler(mainLooper);  
  76.   
  77.                             msg = "curLooper is null";  
  78.   
  79.                      }else{  
  80.   
  81.                             mHandler = new MyHandler(curLooper);  
  82.   
  83.                             msg = "This is curLooper";  
  84.   
  85.                      }  
  86.   
  87.                      mHandler.removeMessages(0);  
  88.   
  89.                      Message m = mHandler.obtainMessage(111, msg);  
  90.   
  91.                      mHandler.sendMessage(m);  
  92.   
  93.               }               
  94.   
  95.        }  
  96.   
  97. }  

 

 

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

 

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

 

 

Java代码  

  1. new Handler(Looper.getMainLooper()).sendMessage(msg);  

IoHandler所在的线程给主线程发送消息(looper是主线程的,消息也就放在主线程的消息队列里了)

但是在主线程的handleMessage方法中得不到消息,尝试失败。

 

    那么怎么办呢,让IoHandler持有主线程的handler引用,具体做法有两种方式:

    1.  参数传递,把主线程的handler通过参数传递的形式传到IoHandler中。

    2. 静态变量,把主线程的handler申明为公共静态变量

    

Java代码  

  1. public static Handler mainHandler;  

 这样在Iohandler中使用

    

Java代码  

  1. welcomeActivity.mainHandler.sendMessage(msg);  

 这两种方式在主线程的  handleMessage的方法中都可以得到IoHandler发送的消息。

 本人使用的是静态变量解决的,因为有好几个来实现通信,参数传递太麻烦。

 

 那为什么我的第一种尝试是失败的呢,我是把消息放到主线程的消息队列了啊,这就要看android的一些实现机制了。

 通过网络和android的api,本人的理解如下:

 Looper是MessageQueue和Handler沟通的桥梁,Handler通过Looper把消息放入消息队列(MessageQueue),你想把消息发给谁,就把谁的looper作为参数传给Handler

 

Java代码  

  1. 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中的一些问题,可能有理解错的地方,请大大们指出来。

  我的疑惑是难道子线程必须持有主线程的引用才可以给主线程发送消息吗?要知道我们的子线程并不一定和主线程一个类,可能在别的类中,这个引用传递实在太麻烦了,期望有更好的解决方式。

 

posted @ 2015-05-29 17:08  guoliuya  阅读(2197)  评论(0编辑  收藏  举报