不少Android初學(xué)者可能覺得,說到多線程就是Handler相關(guān)的知識。其實這種理解非常片面。本篇文章詳細(xì)總結(jié)一下android中的多線程。
多線程的幾種實現(xiàn)方式:
- extends Thread:
class MyFirstThread extends Thread{
@Override
public void run() {
super.run();
Log.d(TAG,"thread id + " + Thread.currentThread());
}
}
主線程中對其調(diào)用:
MyFirstThread t = new MyFirstThread();
t.start();
- implements Runnable:
class MySecondThread implements Runnable {
@Override
public void run() {
Log.d("xlq111","thread id + " + Thread.currentThread());
}
}
主線程中對其調(diào)用時,需要將其放到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);
}
}
調(diào)用方式:
MyThirdThread thread = new MyThirdThread();
thread.execute();
- 線程池(此篇先不介紹)
線程間的通信:
此時便是多線程的核心機制:Handler機制。此時幾個先介紹幾個類:
Handler:用于發(fā)送和處理Message和Runnable對象;
MessageQueue:消息隊列,用于存放通過Handler發(fā)布的消息;
Looper:用于從MessageQueue中取出消息(Message)對象,并發(fā)送給Handler處理;
Message:消息的類型,里面包含幾個實例對象
各個類之前的對應(yīng)關(guān)系:
一個Handler對應(yīng)一個Looper,一個Looper可以對應(yīng)多個Handler。
一個Looper 只擁有一個MessageQueue,所以多個Handler可以共享一個MessageQueue,從而達(dá)到消息共享的目的。
通信方式:Handler有兩種工作體系來完成子線程handler的發(fā)送
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的接收:
復(fù)寫handleMessage方法,實現(xiàn)接收到數(shù)據(jù)之后的操作。
Handler造成的內(nèi)存溢出(OOM):
看代碼:
private Handler mHandler = new Handler() {
@Override
public void handleMessage(Message msg) {
mTextView.setText("");
}
};
這種常見的Handler的創(chuàng)建過程,會有可能造成內(nèi)存溢出。原因是因為mHandler是非靜態(tài)匿名內(nèi)部類的實例,持有對外部類Activity的引用,當(dāng)Activity走OnDestroy方法時,如果此時MessageQueue中還有Message沒有處理完,Message對handler持有引用,handler對activity持有引用,導(dǎo)致Activity無法被GC回收,導(dǎo)致內(nèi)存泄漏。
正確的寫法應(yīng)該是:
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方法中調(diào)用mHandler.removeCallbacksAndMessages(null)來將Message清空,所以以上寫法,不會造成OOM。
多說幾句:
如果要在子線程中創(chuàng)建Looper或者主線程中的Looper為空,必須使用Looper.prepare()方法來創(chuàng)建Looper;
創(chuàng)建Message時,推薦使用Message.obtain()或者Handler.obtatinMessage,因為通過這兩個方法得到的對象是從對象回收池中得到,也就是說是復(fù)用已經(jīng)處理完的Message對象,而不是重新生成一個新對象,這樣對內(nèi)存開銷較小。
就寫到這,如有遺漏或錯誤,請指出。