編輯:關於Android編程
線程也是造成內存洩露的一個重要的源頭。線程產生內存洩露的主要原因在於線程生命周期的不可控。
看一下下面是否存在問題
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(){ } }
這段代碼很平常也很簡單,是我們經常使用的形式。
真的沒有問題嗎
我們思考一個問題:假設MyThread的run函數是一個很費時的操作,當我們開啟該線程後,將設備的橫屏變為了豎屏,
一般情況下當屏幕轉換時會重新創建Activity,按照我們的想法,老的Activity應該會被銷毀才對,然而事實上並非如此。
由於我們的線程是Activity的內部類,所以MyThread中保存了Activity的一個引用,當MyThread的run函數沒有結束時,
MyThread是不會被銷毀的,因此它所引用的老的Activity也不會被銷毀,因此就出現了內存洩露的問題。
這種線程導致的內存洩露問題應該如何解決呢?
代碼如下:
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 { WeakReferencemThreadActivityRef; public MyThread(ThreadAvoidActivity activity) { mThreadActivityRef = new WeakReference ( activity); } @Override public void run() { super.run(); if (mThreadActivityRef == null) return; if (mThreadActivityRef.get() != null) mThreadActivityRef.get().dosomthing(); // dosomthing } } }
上面的兩個步驟其實是切換兩個對象的雙向強引用鏈接
靜態內部類:切斷Activity 對於 MyThread的強引用。
弱引用: 切斷MyThread對於Activity 的強引用。
有些人喜歡用Android提供的AsyncTask,但事實上AsyncTask的問題更加嚴重,
Thread只有在run函數不結束時才出現這種內存洩露問題,然而AsyncTask內部的實現機制是運用了ThreadPoolExcutor,
該類產生的Thread對象的生命周期是不確定的,是應用程序無法控制的,
因此如果AsyncTask作為Activity的內部類,就更容易出現內存洩露的問題。
在看android聯系人2.3源碼的時候看到一個類WeakAsyncTask, 內部用到了WeakReference軟引用, 這樣可以解決內存洩露的問題; 其實給AysncTask加上static, 靜態的內部類不會持有對外部類的引用, 就能夠解決問題, 只不過這樣如果AysncTask的方法用到的成員變量都需要加上static;
為了避免開發者在UI線程上做耗時操作,Android提供了不少異步API,其中之一就是AsyncTask。而對於某些頻繁操作mysql" target="_blank" title="MySQL知識庫">數據庫的應用(例如,Phonebook)而言,需要一種異步的並且低耗資源的(低耗是兩個方面的事情,要麼是你占有的多點,但是能快速釋放;要麼是你本身就占有的少。這兩種都可以保證其它應用有資源可用)組件。所以,那就來個WeakAsyncTask吧,唔,美妙的產物,既保證占有資源的快速釋放,又保證操作是異步進行。
那為什麼不是soft reference呢?
這個,來看看weak和soft兩者的區別:
* A SoftReference should be cleared and enqueued as late as possible, that is, in case the VM is in danger of running out of memory.
* A WeakReference may be cleared and enqueued as soon as is known to be weakly-referenced.
下面是WeakAsyncTask的源碼:
public abstract class WeakAsyncTask
extends AsyncTask {
protected WeakReference mTarget;
public WeakAsyncTask(WeakTarget target) {
mTarget = new WeakReference(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
}
}
使用也很簡單, 用法也幾乎和AsyncTask一樣:
private static class MyTask extends WeakAsyncTask {
public MyTask(MainActivity target) {
super(target);
}
@Override
protected String doInBackground(MainActivity target, Void... params) { // 獲取context,
// 執行一些操作
Context context = target;
return "Hello Android !!!!!";
}
@Override
protected void onPostExecute(MainActivity target, String s) {
// 執行操作
}
}
直接調用執行:
new MyTask(this).execute();
其實還可以根據這個思想寫一個WeakHandler!
今天面試被問及了一個問題:Activity A、Activity B,Activity A 被B覆蓋的時候,Activity生命周期中哪幾個方法被調用了?Activity
好久沒有發博客了,現在工作忙了,底層代碼跟蹤學習的東西很久沒有做成文檔了,雖然博客寫的爛,但是再寫的過程中,能更清晰的認識到自己那個地方還不清晰,不明白。這樣能更好的嘴一
今天給大家帶來一點干貨,就是橫向循環滾動的廣告條。有點類似淘寶的banner廣告位,可以手勢滑動,也會依據固定時間間隔自動滾動,滑到盡頭時會一直循環。過渡非常
上一篇文章中,簡單介紹了一下android數據庫的一些基本概念,那麼從本節開始,就實戰一下Android數據庫的創建和升級。 上文中,也介紹了,SQLiteOpenHel