我有一個加載並顯示較大位圖的活動。冒險的生意擺在首位,但我們在使用BitmapFactory使用下面的標準方法加載:Android內存泄漏導致方向更改和垃圾回收的性質
private static Bitmap decodeSampledBitmapFromFile(String filepath, int reqWidth,int orientation) {
final BitmapFactory.Options options = new BitmapFactory.Options();
options.inJustDecodeBounds = true;
BitmapFactory.decodeFile(filepath,options);
if(orientation==0){
options.inSampleSize = calculateInSampleSizeWidth(options, reqWidth);
// Decode bitmap with inSampleSize set
options.inJustDecodeBounds = false;
Bitmap d = BitmapFactory.decodeFile(filepath,options);
return Bitmap.createScaledBitmap(d, reqWidth, d.getHeight()*reqWidth/d.getWidth(), true);
}
else{
options.inSampleSize = calculateInSampleSizeHeight(options,reqWidth);
options.inJustDecodeBounds = false;
Bitmap d = BitmapFactory.decodeFile(filepath,options);
return Bitmap.createScaledBitmap(d, d.getWidth()*reqWidth/d.getHeight(), reqWidth, true);
}
}
private static int calculateInSampleSizeWidth(BitmapFactory.Options options, int reqWidth) {
int inSampleSize = 1;
if (options.outWidth > reqWidth) {
final int halfWidth = options.outWidth/2;
while ((halfWidth/inSampleSize) > reqWidth) {
inSampleSize *= 2;
}
}
return inSampleSize;
}
該位圖的加載到ImageView的是在的AsyncTask做如下圖所示:
private static class LoadBitmapTask extends AsyncTask<String, Void, Bitmap>{
private ViewSampleActivity _activity;
public LoadBitmapTask(ViewSampleActivity activity){
this._activity = activity;
}
public void detach(){
this._activity = null;
}
@Override
protected Bitmap doInBackground(String... params) {
try{
String filename = params[0];
Display display = _activity.getWindowManager().getDefaultDisplay();
Point size = new Point();
display.getSize(size);
int orientation = getCameraPhotoOrientation(_activity,Uri.fromFile(new File(filename)),filename);
Bitmap d = null;
d = decodeSampledBitmapFromFile(filename, (int)(((double)size.x)*0.85),orientation);
d = rotateBitmapAppropriately(_activity,Uri.fromFile(new File(filename)),filename,d);
return d;
}
catch(Exception e){
return null;
}
}
@Override
protected void onPostExecute(Bitmap result){
try{
_activity.sampleImageView.setImageBitmap(result);
_activity.sampleImageView.setVisibility(View.VISIBLE);
_activity.sampleImageView.getLayoutParams().height = result.getHeight();
_activity.sampleImageView.getLayoutParams().width = result.getWidth();
_activity.viewSampleLayout.getLayoutParams().height = LayoutParams.WRAP_CONTENT;
_activity.hasPicture = true;
}
catch(Exception e){
e.printStackTrace();
}
}
}
爲了儘量避免內存泄漏,我已經重載了activity的onStop方法從AsyncTask中分離活動。
@Override
public void onStop(){
if(this.loadBitmapTask!=null){
loadBitmapTask.detach();
}
super.onStop();
}
現在,我看到的奇怪行爲是,活動在第一次運行時加載得很好。方向更改後,活動將被正確重新加載。但是,經過五次左右的方向更改後,應用程序會因內存不足錯誤而崩潰。位圖似乎是明顯的罪魁禍首。我沒有保存任何ui元素或位圖或任何東西的靜態副本,所以我想知道,如果這些內存不足錯誤是由於內存泄漏。
有問題的活動是活動層次結構的最後一個。層次結構的根,主要活動,有一個帶有WeakReference的android Handler對象,也是一個管理藍牙網絡線程的持久片段。層次結構中的第二個活動是一個簡單的ListActivity。
相關活動的父活動會對Java的垃圾回收活動產生影響嗎?
你是如何管理AsyncTask跨方向變化的重新附加? – 2014-11-14 15:09:46
我不是,我只是運行另一個,讓舊的一個試試趕上忘記。 – user1843784 2014-11-14 15:56:59
所以,如果你旋轉4次,有可能有4個AsyncTasks在那裏,每個都有自己的位圖? – 2014-11-14 15:59:32