不少Android初学者可能觉得,说到多线程就是Handler相关的知识。其实这种理解非常片面。本篇文章详细总结一下android中的多线程。
多线程的几种实现方式:
- extends Thread:
class MyFirstThread extends Thread{
@Override
public void run() {
super.run();
Log.d(TAG,"thread id + " + Thread.currentThread());
}
}
主线程中对其调用:
MyFirstThread t = new MyFirstThread();
t.start();
- implements Runnable:
class MySecondThread implements Runnable {
@Override
public void run() {
Log.d("xlq111","thread id + " + Thread.currentThread());
}
}
主线程中对其调用时,需要将其放到Thread中:
Thread t = new Thread(new MySecondThread());
t.start();
- FutureTask (此方式用的较少)
Callable<String > callable = new Callable<String>() {
@Override
public String call() throws Exception {
Log.d("xlq111","task thread = " + Thread.currentThread());
return Thread.currentThread().toString();
}
};
FutureTask<String> task = new FutureTask<>(callable);
Thread t = new Thread(task);
t.start();
- AsycTask (这个很熟悉)
class MyThirdThread extends AsyncTask<URL,Integer,Long>{
@Override
protected void onPreExecute() {
super.onPreExecute();
}
@Override
protected Long doInBackground(URL... urls) {
return null;
}
@Override
protected void onProgressUpdate(Integer... values) {
super.onProgressUpdate(values);
}
@Override
protected void onPostExecute(Long aLong) {
super.onPostExecute(aLong);
}
}
调用方式:
MyThirdThread thread = new MyThirdThread();
thread.execute();
- 线程池(此篇先不介绍)
线程间的通信:
此时便是多线程的核心机制:Handler机制。此时几个先介绍几个类:
Handler:用于发送和处理Message和Runnable对象;
MessageQueue:消息队列,用于存放通过Handler发布的消息;
Looper:用于从MessageQueue中取出消息(Message)对象,并发送给Handler处理;
Message:消息的类型,里面包含几个实例对象
各个类之前的对应关系:
一个Handler对应一个Looper,一个Looper可以对应多个Handler。
一个Looper 只拥有一个MessageQueue,所以多个Handler可以共享一个MessageQueue,从而达到消息共享的目的。
通信方式:Handler有两种工作体系来完成子线程handler的发送
post:可以post一个Runnable对象到MessageQueue中,存在下 列几种post方法
post(Runnable);
postDelayed(Runnable,long);
postAtTime(Runnable,long);
sendMessage:可以Send一个Message对象到MessageQueue对,存在如下方法
sendMessage(Message);
sendEmptyMessage(int);
sendMessageDelayed(Message,long);
sendMessageAtTime(Message,long);
主线程handler的接收:
复写handleMessage方法,实现接收到数据之后的操作。
Handler造成的内存溢出(OOM):
看代码:
private Handler mHandler = new Handler() {
@Override
public void handleMessage(Message msg) {
mTextView.setText("");
}
};
这种常见的Handler的创建过程,会有可能造成内存溢出。原因是因为mHandler是非静态匿名内部类的实例,持有对外部类Activity的引用,当Activity走OnDestroy方法时,如果此时MessageQueue中还有Message没有处理完,Message对handler持有引用,handler对activity持有引用,导致Activity无法被GC回收,导致内存泄漏。
正确的写法应该是:
private static class MyHandler extends Handler {
private WeakReference<Context> reference;
public MyHandler(Context context) {
reference = new WeakReference<>(context);//这里传入activity的上下文
}
@Override
public void handleMessage(Message msg) {
MainActivity activity = (MainActivity) reference.get();
if(activity != null){
activity.mTextView.setText("");
}
}
}
由于handler持有的是activity的弱引用,弱引用可以被GC回收。另外还未处理完的Message,可以在onDestroy方法中调用mHandler.removeCallbacksAndMessages(null)来将Message清空,所以以上写法,不会造成OOM。
多说几句:
如果要在子线程中创建Looper或者主线程中的Looper为空,必须使用Looper.prepare()方法来创建Looper;
创建Message时,推荐使用Message.obtain()或者Handler.obtatinMessage,因为通过这两个方法得到的对象是从对象回收池中得到,也就是说是复用已经处理完的Message对象,而不是重新生成一个新对象,这样对内存开销较小。
就写到这,如有遗漏或错误,请指出。