Android內存泄露之Thread
線程也是造成內存泄露的一個重要的源頭。線程產生內存泄露的主要原因在于線程生命周期的不可控。
1.看一下下面是否存在問題
/** @version 1.0.0 * @author Abay Zhuang <br/> * Create at 2014-7-17 */
public class ThreadActivity extends Activity { public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); new MyThread().start(); }
private class MyThread extends Thread { @Override public void run() { super.run(); dosomthing(); } } private void dosomthing(){ }
}</pre>
這段代碼很平常也很簡單,是我們經常使用的形式。真的沒有問題嗎
我們思考一個問題:假設MyThread的run函數是一個很費時的操作,當我們開啟該線程后,將設備的橫屏變為了豎屏,一般情況下當屏幕轉換時會重新創建Activity,按照我們的想法,老的Activity應該會被銷毀才對,然而事實上并非如此。由于我們的線程是Activity的內部類,所以MyThread中保存了Activity的一個引用,當MyThread的run函數沒有結束時,MyThread是不會被銷毀的,因此它所引用的老的Activity也不會被銷毀,因此就出現了內存泄露的問題。
2.這種線程導致的內存泄露問題應該如何解決呢?
第一、將線程的內部類,改為靜態內部類。
第二、在線程內部采用弱引用保存Context引用。 代碼如下:
/*
- @version 1.0.0
- @author Abay Zhuang <br/>
- Create at 2014-7-17
*/
public class ThreadAvoidActivity extends Activity {
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
new MyThread(this).start();
}
private void dosomthing() {
}
private static class MyThread extends Thread {
WeakReference<ThreadAvoidActivity> mThreadActivityRef;
public MyThread(ThreadAvoidActivity activity) {
mThreadActivityRef = new WeakReference<ThreadAvoidActivity>(
} @Override public void run() { super.run(); if (mThreadActivityRef == null)activity);
if (mThreadActivityRef.get() != null)return;
// dosomthing } } }</pre>mThreadActivityRef.get().dosomthing();
上面的兩個步驟其實是切換兩個對象的雙向強引用鏈接
靜態內部類:切斷Activity 對于 MyThread的強引用。
弱引用: 切斷MyThread對于Activity 的強引用。
3.AsynTask 內部類會如何呢?
有些人喜歡用Android提供的AsyncTask,但事實上AsyncTask的問題更加嚴重, Thread只有在run函數不結束時才出現這種內存泄露問題,然而AsyncTask內部的實現機制是運用了ThreadPoolExcutor, 該類產生的Thread對象的生命周期是不確定的,是應用程序無法控制的, 因此如果AsyncTask作為Activity的內部類,就更容易出現內存泄露的問題。
代碼如下:
/*
- 弱引用
- @version 1.0.0
- @author Abay Zhuang <br/>
- Create at 2014-7-17
*/
public abstract class WeakAsyncTask<Params, Progress, Result, WeakTarget>
extends AsyncTask<Params, Progress, Result> {
protected WeakReference<WeakTarget> mTarget;
public WeakAsyncTask(WeakTarget target) {
mTarget = new WeakReference<WeakTarget>(target);
}
@Override
protected final void onPreExecute() {
final WeakTarget target = mTarget.get();
if (target != null) {
this.onPreExecute(target);
}
}
@Override
protected final Result doInBackground(Params... params) {
final WeakTarget target = mTarget.get();
if (target != null) {
return this.doInBackground(target, params);
} else {
return null;
}
}
@Override
protected final void onPostExecute(Result result) {
final WeakTarget target = mTarget.get();
if (target != null) {
this.onPostExecute(target, result);
}
}
protected void onPreExecute(WeakTarget target) {
// Nodefaultaction
}
protected abstract Result doInBackground(WeakTarget target,
Params... params);
protected void onPostExecute(WeakTarget target, Result result) {
// Nodefaultaction
}
}</pre>