线程间通信之Handler小实验
转载请标明地址,谢谢:http://blog.youkuaiyun.com/pfugwtg/article/details/50347341
目录
前言
由于项目需要,今天找了一些关于线程间通信的知识看了一下,然后自己实验总结了一下,以此备忘。
其它线程向UI线程传递消息之类的我就不写了,这类知识网上可以找一大堆,我这里主要是讲一下UI线程以外的线程间通讯。
基本知识
在非UI线程中若要创建Handler,则必需调用Looper.prepare()和Looper.loop(),但对于它们的具体调用时机,童鞋们又知道多少呢,嘿嘿嘿…
好了,肉戏来了。。。
第一段代码
package com.example.androidtest.thread.communicate;
import android.os.Handler;
import android.os.Looper;
import android.os.Message;
import android.util.Log;
public class ThreadsCommunicate {
private static final String TAG = "ThreadsCommunicate";
private Thread aThread = null;
private Handler mHandler = null;
public ThreadsCommunicate() {
aThread = new AThread();
aThread.start();
}
public void sendMsg() {
if(null != mHandler) {
Log.d(TAG, "sendMsg success!");
mHandler.obtainMessage().sendToTarget();
}
else {
Log.e(TAG, "sendMsg failed...");
}
}
public void destroy() {
if(null != mHandler) {
mHandler.getLooper().quit();
}
}
private class AThread extends Thread {
@Override
public void run() {
this.setName("myAThread");
Looper.prepare();
Log.i(TAG, "AThread run()");
mHandler = new Handler() {
@Override
public void handleMessage(Message msg) {
Log.i(TAG, "Thread name:" + this.getLooper().getThread().getName());
super.handleMessage(msg);
}
};
Looper.loop();
super.run();
}
}
}
调用部分代码:
package com.example.androidtest;
import com.example.androidtest.thread.communicate.ThreadsCommunicate;
import android.app.Activity;
import android.os.Bundle;
import android.view.View;
public class MainActivity extends Activity{
private ThreadsCommunicate mThreadsCommunicate;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
mThreadsCommunicate = new ThreadsCommunicate();
}
public void viewOnClick(View view) {
switch (view.getId()) {
case R.id.btn_send:
mThreadsCommunicate.sendMsg();
break;
case R.id.btn_destroy:
mThreadsCommunicate.destroy();
break;
default:
break;
}
}
}
1、这一部分代码运行后DDMS如图:
点击Send按钮后DDMS不变,日志输出如图:
2、退出应用后再次进入应用后DDMS变成这样:
Oh,my god!我们发现多了一个线程,这是为什么???
3、点击destroy按钮后的DDMS:
奇迹发生了,线程少了一个!!!看到这里,我想大家已经知道原因了吧:)
小结1:
在非UI线程中创建Handler(调用Looper.prepare()和Looper.loop())后,在不需要的时候,必需调用Looper.quit()方法;否则,创建该Handler的线程将无法被释放。想想吧,如果每执行一次退出/进入程序操作就多一个线程,那最后,嘿嘿,结果你懂的。。。
第二段代码
在这里,我们只要改一点点代码就可以了:
package com.example.androidtest.thread.communicate;
import android.os.Handler;
import android.os.Looper;
import android.os.Message;
import android.util.Log;
public class ThreadsCommunicate {
private static final String TAG = "ThreadsCommunicate";
private Thread aThread = null;
private Handler mHandler = null;
public ThreadsCommunicate() {
aThread = new AThread();
aThread.start();
}
public void sendMsg() {
if(null != mHandler) {
Log.d(TAG, "sendMsg success!");
mHandler.obtainMessage().sendToTarget();
}
else {
Log.e(TAG, "sendMsg failed...");
}
}
public void destroy() {
if(null != mHandler) {
mHandler.getLooper().quit();
}
}
private class AThread extends Thread {
@Override
public void run() {
this.setName("myAThread");
Looper.prepare();
Looper.loop();//嘿嘿,就是把这一行从下面移到了这儿,看看结果吧
Log.i(TAG, "AThread run()");
mHandler = new Handler() {
@Override
public void handleMessage(Message msg) {
Log.i(TAG, "Thread name:" + this.getLooper().getThread().getName());
super.handleMessage(msg);
}
};
super.run();
}
}
}
改动即是注释部分,结果怎样呢,我们来看看:
1、程序启动后,日志是空的!!!
好吧,我知道你们一定不相信,肯定怀疑我的Logcat坏了,为了打破你们的幻想,我们接着看下面:
2、点击Send按钮后的Logcat
哈哈,这下你们死心了吧,看日志就知道了:mHandler==null。
小结2:
在非UI线程中创建Handler时,创建Handler的时机必须是在Looper.prepare()和Looper.loop()之间,并且所有的有效代码都必需在Looper.loop()之前;因为就实验结果来看,貌似程序是无法执行到Looper.loop()之后的。
结尾
今天因为项目开发,所以在网上在找一些线程间通信的知识,然后自己也粗略看了一些(因为都知道个大概,但细节不确定),但还是没能解决我的一些疑惑;于是我自己动手做了这个小实验,并将实验过程以博文方式记录下来,权当对网上的其它资料的一个补充(当然,若是网上其它还有这方面的文章,那就是我粗心没看到了)。