Activity启动后点击一个界面按钮后会开启一个服务(暂定为padService),在padService中会启动一个线程(暂定为Thread-3)发起Socket连接。我们项目中使用mina作为socket通信框架,用过mina的同志们应该熟悉,Thread-3只是负责监听,具体的消息处理是另外的线程。在我们的IoHandler中处理消息,现在的问题是,我需要在IoHander的sessionOpened方法中给Activity一个消息去更新UI界面,这个就涉及到不同线程间的通信了。
网上搜索后,在android中线程间通信使用Handler,Looper,Message这几个对象(不熟悉这些概念的同志们请自己查下)。
这是网上的一个使用例子:
<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>
这个没有问题,基本上三个对象的使用也很清楚,myHandler虽然是由子线程new出来的,但主线程持有引用,在我们的项目中不能用,因为我们几个线程属于不同的类,我尝试用下面的方法解决:
在IoHandler中new一个android的handler,参数为主线程的Looper:
<span style="font-size: medium;">new Handler(Looper.getMainLooper()).sendMessage(msg);</span>
IoHandler所在的线程给主线程发送消息(looper是主线程的,消息也就放在主线程的消息队列里了)
但是在主线程的handleMessage方法中得不到消息,尝试失败。
那么怎么办呢,让IoHandler持有主线程的handler引用,具体做法有两种方式:
1. 参数传递,把主线程的handler通过参数传递的形式传到IoHandler中。
2. 静态变量,把主线程的handler申明为公共静态变量
<span style="font-size: medium;">public static Handler mainHandler;</span>
这两种方式在主线程的 handleMessage的方法中都可以得到IoHandler发送的消息。
本人使用的是静态变量解决的,因为有好几个来实现通信,参数传递太麻烦。
那为什么我的第一种尝试是失败的呢,我是把消息放到主线程的消息队列了啊,这就要看android的一些实现机制了。
通过网络和android的api,本人的理解如下:
Looper是MessageQueue和Handler沟通的桥梁,Handler通过Looper把消息放入消息队列(MessageQueue),你想把消息发给谁,就把谁的looper作为参数传给Handler
<span style="font-size: medium;">newHandler(Looper looper);</span>
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中的一些问题,可能有理解错的地方,请大大们指出来。
我的疑惑是难道子线程必须持有主线程的引用才可以给主线程发送消息吗?要知道我们的子线程并不一定和主线程一个类,可能在别的类中,这个引用传递实在太麻烦了,期望有更好的解决方式。