W mojej aplikacji używam listview i listadapter. Kiedy kliknie się na pewną podstronę w liście, istnieje klikalny widok tekstowy, który ładuje kilka bitmap do przewijania - i ten widok przewijania jest pokazywany na liście alertów.wyciek pamięci pomimo używania słabej referencji
Wszystko to dzieje się w klasie, która rozszerza BaseExpandableListAdapter i po kliknięciu tego łącza tekstowego - wywoływana jest statyczna klasa wewnętrzna odpowiedzialna za ładowanie wszystkich tych (9) bitmap. Ta wewnętrzna klasa rozszerza asynktas.
Zanim te mapy bitowe zostaną załadowane do przewijania, wywoływane są dwie statyczne metody tej klasy wewnętrznej, które przeskalowują bitampy do rozmiaru pasującego do ekranu. Tutaj używam Bitmapfactory.decoderesource i Bitmap.scaledownBitmap.
Wszystko to działa FINE, .. ALE program cierpi na brak pamięci. Ten przeciek był dość duży, ponieważ ta wewnętrzna klasa była niestatyczna. Więc przeciek został zredukowany, czyniąc tę wewnętrzną klasę statyczną. Tak - zmniejszone, ale nie wyeliminowane.
Dokonałem również słabej oceny kilku obiektów, ale bez powodzenia. Na przykład - zrobiłem słabe odniesienie do obiektu, który odnosi się do klasy wewnętrznej. Zawarłem słabe odniesienie do kontekstu przekazywanego do klasy wewnętrznej. Wprowadziłem nawet słabe odniesienie do bitmap. Bez powodzenia.
Wielkość mojego telefonu Samsung Galazy s3 wynosi 64 MB. Kiedy listview z wszystkimi jego podelementami jest najpierw załadowany używaną stertą, ma około 17 MB. Następnie, po załadowaniu 9 bitmap, jest to ok. 42 MB. Jeśli kliknę na inny podzespół z obrazami używana sterty jest taka sama - ale po dalszym kliknięciu i załadowaniu bitmap sterty nagle marnie do 47 MB ... to ten sam scenariusz .... stoi przez chwilę - a następnie do 52 MB .... 56 MB. Muszę więc kliknąć i wczytać bitmapy, aby uzyskać brak pamięci. Powiedzmy 15-20 minut intensywnego użytkowania.
Podsumowanie: Aby statyczne klasy wewnętrzne pomogły mi zmniejszyć wyciek pamięci. Ale pomimo słabych referencji kilku obiektów (zwłaszcza kontekstu) nie udało mi się jeszcze bardziej zmniejszyć wycieku.
Wszelkie sugestie?
Poniższy kod jest nieco brudny ....
static class BitmapWorkerTask extends AsyncTask <Integer, Void, Bitmap[]> {
private int[] data;
private int[] width, height;
private int nmbrOfImages;
private String[] scrollText;
private ImageView mImage;
private View view;
private LayoutInflater factory;
private AlertDialog.Builder alertadd;
private Context context;
private WeakReference <Context> sc;
private WeakReference <ImageView> mImageV;
private WeakReference <Bitmap[]> bitmapV;
public BitmapWorkerTask(int[] width, int[] height, int nmbrOfImages, String[] scrollText, Context context) {
this.width = width;
this.height = height;
this.nmbrOfImages = nmbrOfImages;
this.scrollText = scrollText;
this.context = context;
mImage = null;
view = null;
factory = null;
alertadd = null;
System.gc();
sc = new WeakReference <Context> (context);
try {
for (int i = 0; i < scaledBitmap.length; i++) {
scaledBitmap[i].recycle();
scaledBitmap[i] = null;
}
} catch (NullPointerException ne) {
System.out.println("nullpointerexception ... gick inte recycla bitmapbilder");
}
switch (nmbrOfImages) {
case 0:
data = new int[1];
break;
case 1:
data = new int[3];
break;
case 2:
data = new int[5];
break;
case 3:
data = new int[9];
break;
}
}
@Override
protected Bitmap[] doInBackground(Integer ... params) {
switch (nmbrOfImages) {
case 0:
data[0] = params[0];
break;
case 1:
data[0] = params[0];
data[1] = params[1];
data[2] = params[2];
break;
case 2:
data[0] = params[0];
data[1] = params[1];
data[2] = params[2];
data[3] = params[3];
data[4] = params[4];
break;
case 3:
data[0] = params[0];
data[1] = params[1];
data[2] = params[2];
data[3] = params[3];
data[4] = params[4];
data[5] = params[5];
data[6] = params[6];
data[7] = params[7];
data[8] = params[8];
break;
}
alertadd = new AlertDialog.Builder(sc.get());
factory = LayoutInflater.from(sc.get());
Bitmap[] bm = decodeSampledBitmapFromResource(sc.get().getResources(), data, width, height);
bitmapV = new WeakReference <Bitmap[]> (bm);
return bitmapV.get();
}
protected void onPostExecute(Bitmap[] bitmap) {
switch (nmbrOfImages) {
case 0:
if (view == null) {
view = factory.inflate(R.layout.alertviews, null);
}
mImage = (ImageView) view.findViewById(R.id.extra_img);
mImage.setImageBitmap(bitmap[0]);
alertadd.setView(view);
alertadd.setNeutralButton("Here!", new DialogInterface.OnClickListener() {
public void onClick(DialogInterface dlg, int sumthin) {
}
});
alertadd.show();
break;
case 1:
if (view == null) {
view = factory.inflate(R.layout.alertviews2, null);
}
mImage = (ImageView) view.findViewById(R.id.img1);
mImage.setImageBitmap(bitmap[0]);
mImage = (ImageView) view.findViewById(R.id.img2);
mImage.setImageBitmap(bitmap[1]);
mImage = (ImageView) view.findViewById(R.id.img3);
mImage.setImageBitmap(bitmap[2]);
try {
TextView mText2 = (TextView) view.findViewById(R.id.text_img1_scrollview);
mText2.setText(scrollText[0]);
mText2 = (TextView) view.findViewById(R.id.text_img2_scrollview);
mText2.setText(scrollText[1]);
mText2 = (TextView) view.findViewById(R.id.text_img3_scrollview);
mText2.setText(scrollText[2]);
} catch (NullPointerException ne) {
System.out.println("nullpointerexception ... TextView i metoden onPostExecute");
}
alertadd.setView(view);
alertadd.setNeutralButton("Here!", new DialogInterface.OnClickListener() {
public void onClick(DialogInterface dlg, int sumthin) {
}
});
alertadd.show();
break;
case 2:
if (view == null) {
view = factory.inflate(R.layout.alertviews3, null);
}
mImage = (ImageView) view.findViewById(R.id.img1);
mImage.setImageBitmap(bitmap[0]);
mImage = (ImageView) view.findViewById(R.id.img2);
mImage.setImageBitmap(bitmap[1]);
mImage = (ImageView) view.findViewById(R.id.img3);
mImage.setImageBitmap(bitmap[2]);
mImage = (ImageView) view.findViewById(R.id.img4);
mImage.setImageBitmap(bitmap[3]);
mImage = (ImageView) view.findViewById(R.id.img5);
mImage.setImageBitmap(bitmap[4]);
try {
TextView mText3 = (TextView) view.findViewById(R.id.text_img1_scrollview);
mText3.setText(scrollText[0]);
mText3 = (TextView) view.findViewById(R.id.text_img2_scrollview);
mText3.setText(scrollText[1]);
mText3 = (TextView) view.findViewById(R.id.text_img3_scrollview);
mText3.setText(scrollText[2]);
mText3 = (TextView) view.findViewById(R.id.text_img4_scrollview);
mText3.setText(scrollText[3]);
mText3 = (TextView) view.findViewById(R.id.text_img5_scrollview);
mText3.setText(scrollText[4]);
} catch (NullPointerException ne) {
System.out.println("nullpointerexception ... TextView i metoden onPostExecute");
}
alertadd.setView(view);
alertadd.setNeutralButton("Here!", new DialogInterface.OnClickListener() {
public void onClick(DialogInterface dlg, int sumthin) {
}
});
alertadd.show();
break;
case 3:
if (view == null) {
view = factory.inflate(R.layout.alertviews4, null);
}
AlertDialog.Builder alertadd = new AlertDialog.Builder(context);
mImage = (ImageView) view.findViewById(R.id.img1);
mImage.setImageBitmap(bitmap[0]);
mImage = (ImageView) view.findViewById(R.id.img2);
mImage.setImageBitmap(bitmap[1]);
mImage = (ImageView) view.findViewById(R.id.img3);
mImage.setImageBitmap(bitmap[2]);
mImage = (ImageView) view.findViewById(R.id.img4);
mImage.setImageBitmap(bitmap[3]);
mImage = (ImageView) view.findViewById(R.id.img5);
mImage.setImageBitmap(bitmap[4]);
mImage = (ImageView) view.findViewById(R.id.img6);
mImage.setImageBitmap(bitmap[5]);
mImage = (ImageView) view.findViewById(R.id.img7);
mImage.setImageBitmap(bitmap[6]);
mImage = (ImageView) view.findViewById(R.id.img8);
mImage.setImageBitmap(bitmap[7]);
mImage = (ImageView) view.findViewById(R.id.img9);
mImage.setImageBitmap(bitmap[8]);
try {
TextView mText4 = (TextView) view.findViewById(R.id.text_img1_scrollview);
mText4.setText(scrollText[0]);
mText4 = (TextView) view.findViewById(R.id.text_img2_scrollview);
mText4.setText(scrollText[1]);
mText4 = (TextView) view.findViewById(R.id.text_img3_scrollview);
mText4.setText(scrollText[2]);
mText4 = (TextView) view.findViewById(R.id.text_img4_scrollview);
mText4.setText(scrollText[3]);
mText4 = (TextView) view.findViewById(R.id.text_img5_scrollview);
mText4.setText(scrollText[4]);
mText4 = (TextView) view.findViewById(R.id.text_img6_scrollview);
mText4.setText(scrollText[5]);
mText4 = (TextView) view.findViewById(R.id.text_img7_scrollview);
mText4.setText(scrollText[6]);
mText4 = (TextView) view.findViewById(R.id.text_img8_scrollview);
mText4.setText(scrollText[7]);
mText4 = (TextView) view.findViewById(R.id.text_img9_scrollview);
mText4.setText(scrollText[8]);
} catch (NullPointerException ne) {
System.out.println("nullpointerexception ... TextView i metoden onPostExecute");
}
alertadd.setView(view);
alertadd.setNeutralButton("Here!", new DialogInterface.OnClickListener() {
public void onClick(DialogInterface dlg, int sumthin) {
}
});
alertadd.show();
break;
}
}
/**
*
* @param options
* @param reqW
* @param reqH
* @return
*/
public static int calculateInSampleSize(BitmapFactory.Options options, int reqW, int reqH) {
int imageHeight = options.outHeight;
int imageWidth = options.outWidth;
int inSampleSize = 1;
if (imageHeight > reqH || imageWidth > reqW) {
int heightRatio = Math.round((float) imageHeight/(float) reqH);
int widthRatio = Math.round((float) imageWidth/(float) reqW);
inSampleSize = heightRatio < widthRatio ? heightRatio : widthRatio;
System.out.println("i if-satsen!");
System.out.println("height-ratio: " + heightRatio + "\nwidth-ratio: " + widthRatio);
}
System.out.println("samplesize: " + inSampleSize);
inSampleSize = inSampleSize;
return inSampleSize;
}
@SuppressLint("NewApi")
/**
*
* @param res
* @param resId
* @param reqW
* @param reqH
* @return
*/
public static Bitmap[] decodeSampledBitmapFromResource(Resources res, int[] resId, int[] reqW, int[] reqH) {
scaledBitmap = new Bitmap[resId.length];
BitmapFactory.Options options;
for (int i = 0; i < resId.length; i++) {
options = new BitmapFactory.Options();
options.inJustDecodeBounds = true;
Bitmap bm =BitmapFactory.decodeResource(res, resId[i], options);
System.out.println("ursprunglig bild: h = " + options.outHeight + " w = " + options.outWidth);
options.inSampleSize = calculateInSampleSize(options, reqW[i], reqH[i]);
while (options.outHeight < reqH[i] || options.outWidth < reqW[i]) {
options.inSampleSize--;
System.out.println("räknar nu ner insampleseize\ninSamleSize =" + options.inSampleSize);
}
options.inJustDecodeBounds = false;
bm = BitmapFactory.decodeResource(res, resId[i], options);
System.out.println("innan omskalning: h = " + options.outHeight + " w = " + options.outWidth);
System.out.println("antalet bytes: " + bm.getByteCount());
System.out.println("native free size: " + Debug.getNativeHeapFreeSize());
scaledBitmap[i] = Bitmap.createScaledBitmap(bm, reqW[i], reqH[i], true);
bm.recycle();
bm = null;
}
System.gc();
WeakReference <Bitmap[] > sc = new WeakReference <Bitmap[]> (scaledBitmap);
return sc.get();
}
}
}
Zastosowanie MAT w celu ustalenia, gdzie występuje nieszczelność. – CommonsWare