1,解決使用Bitmap時出現的記憶體溢出
1)及時的銷毀,雖然,系統能夠确認Bitmap配置設定的記憶體最終會被銷毀,但是由于它占用的記憶體過多,是以很可能會超過java堆的限制。是以,在用完Bitmap時,要及時的recycle掉。recycle并不能确定立即就會将Bitmap釋放掉,但是會給虛拟機一個暗示:“該圖檔可以釋放了”。
2)設定一定的采樣率,有時候,我們要顯示的區域很小,沒有必要将整個圖檔都加載出來,而隻需要記載一個縮小過的圖檔,這時候可以設定一定的采樣率,那麼就可以大大減小占用的記憶體。如下面的代碼:
private ImageView preview;
BitmapFactory.Options options = new BitmapFactory.Options();
options.inSampleSize = 2;
Bitmap bitmap = BitmapFactory.decodeStream(cr.openInputStream(uri),
null, options);
preview.setImageBitmap(bitmap);
3)運用軟引用(SoftRefrence),有些時候,我們使用Bitmap後沒有保留對它的引用,是以就無法調用Recycle函數。這時候巧妙的運用軟引用,可以使Bitmap在記憶體快不足時得到有效的釋放。如下例:
private class MyAdapter extends BaseAdapter {
private ArrayList mBitmapRefs = new ArrayList();
private ArrayList mValues;
private Context mContext;
private LayoutInflater mInflater;
MyAdapter(Context context, ArrayList values) {
mContext = context;
mValues = values;
mInflater = (LayoutInflater) context.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
}
public int getCount() {
return mValues.size();
}
public Object getItem(int i) {
return mValues.get(i);
}
public long getItemId(int i) {
return i;
}
public View getView(int i, View view, ViewGroup viewGroup) {
View newView = null;
if(view != null) {
newView = view;
} else {
newView =(View)mInflater.inflate(R.layout.image_view, false);
}
Bitmap bitmap = BitmapFactory.decodeFile(mValues.get(i).fileName);
mBitmapRefs.add(new SoftReference(bitmap)); //此處加入ArrayList
((ImageView)newView).setImageBitmap(bitmap);
return newView;
}
}
2,解決Context引起的記憶體溢出:
在Android平台上,長期保持一些資源的引用,造成一些記憶體不能釋放,帶來的記憶體洩露問題很多。比如Context。
android中的很多資源檔案都需要一個Context引用來加載,如果這些資源沒有被釋放,那麼Context的引用不為null,造成對應的Activity即使 調用了finish()但其占有的記憶體依然不能被釋放。這是 因為在Java或者Android記憶體機制中,頂點的結點釋放前必須保證其他對象沒有調用才能被系統GC回收釋放。我們來看一段代碼:
SoundManager.getInstance(this).play(SoundManger.MAIN_BG_SOUND);
從這段代碼可以看出,聲音管理類是一個單例,它對于整個應用程序來說是全局的,在進入應用的時候建立這個單利直到應用結束,這個單例才會被釋放。大家可以看到這個類在得到單例的時候需要傳遞一個Context對象作為參數,因為要利用Context來加載聲音資源。這就導緻如果目前Activity調用了finish()全依然不能被GC,因為聲音管理類是全局的,它持有了目前Activity的應用,阻止了其被GC。 解決的辦法是盡量使用全局的Context來加載資源。修改如下:
SoundManager.getInstance(this.getApplicationContext).play(SoundManger.MAIN_BG_SOUND);
3,解決Thread 線程引起的記憶體溢出
如下代碼:
private class MyThread extends Thread{
@Override
public void run() {
super.run();
while(bFlag)
{
//do somthing
}
}
MyThread mThread = new MyThread();
mThread.start();
這端代碼 在主線程裡新開了一個線程,并且線上程裡循環處理一些邏輯。問題在于 如果控制線程結束的bFlag如果在Activity銷毀時沒有置為 false 将會産生很嚴重的後果。線程的一個特點是生命周期的不可控。如果Activity銷毀時,沒有結束線程的運作,那麼不僅阻止了Activity被GC,而且大大降低了程式的性能。假如,再重新進入這個Activity,那麼又建立了一個死循環的線程,而之前的那個線程依然在運作,這樣程式就會非常的卡。是以 一定要注意,銷毀Activity時一定要結束線程。
總而言之,想要避免context 相關的記憶體洩漏 ,記住以下幾點:
a.不要對activity 的context 長期引用( 一個activity 的引用的生存周期應該和activity 的生命周期相同)
b.試着使用關于application的 context 來替代和activity相關的context
c.如果一個acitivity 的非靜态内部類的生命周期不受控制,那麼避免使用它;使用一個靜态的内部類并且對其中的activity 使用一個弱引用。解決這個問題的方法是使用一個靜态的内部類,并且對它的外部類有一WeakReference,就像在ViewRoot中内部類W所做的就是這麼個例子。