定义梳理
1、Message: Message Queue中的存放的对象。
Message实例对象的取得,通常使用Message类里的静态方法obtain()。它的创建并不一定是直接创建一个新的实例,而是先从Message Pool(消息池)中看有没有可用的Message实例,存在则直接取出返回这个实例。如果Message Pool中没有可用的Message实例,则才用给定的参数创建一个Message对象。
2、MessageQueue:是一种 数据 结构,是一个消息队列。
每一个线程最多只可以拥有一个MessageQueue数据结构。创建一个线程的时候,并不会自动 创建其MessageQueue。通常使用一个Looper对象对该线程的MessageQueue进行管理。
3、Looper: 是MessageQueue的管理者。
每一个MessageQueue都不能脱离Looper而存在,Looper对象的创建是通过prepare函数来实现的。创建一个Looper对象时,会同时创建一个MessageQueue对象。除了主线程有默认的Looper,其他线程默认是没有MessageQueue对象的,所以,不能接受Message。
4、Handler: 消息的处理者
handler 负责将需要传递的信息封装成Message,通过调用handler 对象的obtainMessage()来实现;将消息传递给Looper,这是通过handler 对象的sendMessage()来实现的。继而由Looper将Message放入MessageQueue中。当Looper对象看到MessageQueue中含有Message,就将其广播出去。
线程间如何传递消息
这里分了四种情况:1、主线程给自己发消息;2、其他线程给主线程发消息;3、主线程给其他线程发送消息;4、其他线程发送消息。为每种情况,我写了一个小的demo实现其基本流程。
1、 主线程给自己发送消息
由于,主线程由系统自动为其创建Looper对象,并开启消息循环,所以,我们在主线程创建Handler对象时不需要显示创建Looper对象。
代码清单一:
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
button = (Button) findViewById(R.id.button);
msg = (TextView) findViewById(R.id.msg);
button.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
//Looper looper = Looper.getMainLooper();
handler = new Handler() {
@Override
public void handleMessage(Message msg) {
// TODO Auto-generated method stub
super.handleMessage(msg);
MainActivity.this.msg.setText("我是主线程的Handler,收到消息:"
+ (String) msg.obj);
}
};
Message msg = handler.obtainMessage(1, 1, 1, "主線程發消息了");
handler.sendMessage(msg);
}
});
}
2、 其他线程给主线程发送消息
其实这里还是要用到主线程的Looper创建handler,所以只要在主线程创建好handler对象然后利用构造或者其他public方法将handler对象传递给其他线程,在其他线程中用主线程的handler发送消息。
代码清单二:
其他线程代码:
package com.example.handlerdemo;
import android.os.Handler;
import android.os.Message;
public class MyThread extends Thread {
private Handler handler;
public MyThread(Handler handler) {
this.handler = handler;
}
@Override
public void run() {
Message msg = handler.obtainMessage(1, 1, 1, "其他线程发消息了");
handler.sendMessage(msg);
}
}
主activity的onCreate方法
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
button = (Button) findViewById(R.id.button);
msg = (TextView) findViewById(R.id.msg);
button.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
//Looper looper = Looper.getMainLooper();
handler = new Handler() {
@Override
public void handleMessage(Message msg) {
// TODO Auto-generated method stub
super.handleMessage(msg);
MainActivity.this.msg.setText("我是主线程的Handler,收到消息:"
+ (String) msg.obj);
}
};
new MyThread(handler).start();
}
});
}
3、主线程给其他线程发送消息
由于要在非主线程中创建handler对象,此时就需要显式启用Looper,如果直接new handler的话会报错误:E/AndroidRuntime( 6173): Uncaught handler: thread Thread-8 exiting due to uncaught exception
E/AndroidRuntime( 6173): java.lang.RuntimeException: Can’t create handler inside thread that has not called Looper.prepare()
代码清单三:
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
new MyThread().start();
button = (Button) findViewById(R.id.button);
textView = (TextView) findViewById(R.id.msg);
button.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
Message message = handler.obtainMessage(1, "主线程发送消息");
handler.sendMessage(message);
}
});
}
class MyThread extends Thread {
@Override
public void run() {
Looper.prepare();
handler = new Handler() {
@Override
public void handleMessage(Message msg) {
// TODO Auto-generated method stub
super.handleMessage(msg);
Log.i("test", "test");
}
};
Looper.loop();
}
}
4、其他线程给自己发送消息
代码清单三:
// class MyHandler extends Handler{
// public MyHandler(Looper looper) {
// super(looper);
// }
// @Override
// public void handleMessage(Message msg) {
// // TODO Auto-generated method stub
// super.handleMessage(msg);
// textView.setText((String)msg.obj);
// }
// }
class MyThread extends Thread{
@Override
public void run() {
Looper.prepare();
handler = new Handler(){
@Override
public void handleMessage(Message msg) {
if (msg.what == 1 && msg.obj.equals("myself")) {
handler = new Handler(Looper.getMainLooper()){
public void handleMessage(Message msg) {
super.handleMessage(msg);
textView.setText((String)msg.obj);
};
};
//handler = new MyHandler(Looper.getMainLooper());
}
Message message = handler.obtainMessage(1, 1, 1, "告诉主线程,我收到自己发送的消息");
handler.sendMessage(message);
}
};
Message message = handler.obtainMessage(1,1,1,"myself");
handler.sendMessage(message);
Looper.loop();
}
}
}
安卓多线程应用场景
Android系统为了提高程序的实时响应能力,不允许在UI线程中进行耗时的操作,否则会出现ANR异常,因此必须将耗时的任务放到非UI线程中执行。Android/Java提供了很多类来帮助大家完成异步操作,比如:Thread类,Timer类,AsyncTask类,HandlerThread类,以及Executor接口。
1. 单项异步任务
场景:文件操作,如下载和拷贝文件
方案:Thread类,AsyncTask类
比较:Thread更适合执行一些不需要跟UI频繁交互的单项任务,而AsyncTask相反
2.定时执行的任务
场景:定时刷新UI
方案:“Thread + sleep”,定时器Timer
比较: Timer是由系统创建异步通知的定时器,会更加准确
3. 工作线程
场景:“生产者–消费者”模式,TCP Server端命令处理程序
方案: “Thread + condition/lock” ,HandlerThread类,线程池Executor
比较:前面的两种方式,都是“串行”的方式在执行“命令”,如果希望提供并发性,同时开启和管理多个线程来执行任务,则可以考虑使用Executor。