1

My problem is mostly like this: strange out of memory issue, and I thought I already solved this by calling recycle(). This Problem occurs in example in my ListView: each Element has 0 to 10 icons. I extended my Adapter to recycle all Bitmaps from convertView which works. after an Item was clicked, I'm showing a detail site which uses same BMP's than my List. But Developing goes on, and I have the need to show everything in Tabs. So my ListView and the DetailView should be shown in the same Tab. After struggling two days with "ActivityGroup" (which is deprecated btw) I decided to use compatibility-package and start programming my Activity which shows the List and the DetailActivity as Fragments. While it seems to work, that my ListViewAdapter recycles every Bitmap from convertView, It doesn't seem to work at my DetailView. Log is telling me that recycle is called, but after 2-3 DetailViews (depending on shown Bitmaps) I get the same old Error. This is my only Activity living inside the TabView:

public class FaultGroup extends FragmentActivity implements OnItemClickListener, OnBackStackChangedListener{




public static final String FRAGMENT_LIST_TAG = "FaultListFragment";
public static final String FRAGMENT_DETAIL_TAG = "FaultDetailFragment";
public static final String TAG = "FaultGroup";


private FragmentManager mFragmentManager;
private FragmentTransaction mTransaction;

private boolean mDetailsShown  = false;

public void onCreate(Bundle icicle){
    super.onCreate(icicle);

    setContentView(R.layout.fragment_layout);

    mFragmentManager = getSupportFragmentManager();
    mFragmentManager.addOnBackStackChangedListener(this);

    FaultReportListFragment fragment = new FaultReportListFragment();

    mTransaction= mFragmentManager.beginTransaction();
    mTransaction.add(R.id.fragment_container, fragment, FRAGMENT_LIST_TAG);
    mTransaction.addToBackStack(null);
    mTransaction.commit();

}

public void onResume(){
    super.onResume();
    LogCat.d(TAG, "onResume");
}

public void onDestroy(){
    super.onDestroy();
    LogCat.d(TAG, "onDestroy");
}

@Override
public void onItemClick(AdapterView<?> parent, View view, int position,
        long id) {
    LogCat.d(TAG, "onItemClick");
    DatabaseReport dbReport = (DatabaseReport)parent.getAdapter().getItem(position);
    fiScheduleDeviationReport report = dbReport.read();
    Bundle arguments = new Bundle();
    arguments.putParcelable(FaultReportDetailFragment.KEY_REPORT_EXTRA, report);

    FaultReportDetailFragment fragment = new FaultReportDetailFragment();
    fragment.setArguments(arguments);
    mDetailsShown = true;

    mTransaction = mFragmentManager.beginTransaction();
    mTransaction.replace(R.id.fragment_container, fragment, FRAGMENT_DETAIL_TAG);
    mTransaction.addToBackStack(null);
    mTransaction.setTransition(FragmentTransaction.TRANSIT_FRAGMENT_FADE);
    mTransaction.commit();

}
@Override
public void onBackPressed(){
    mDetailsShown = false;
    super.onBackPressed();
    /*
    mTransaction = mFragmentManager.beginTransaction();
    mTransaction.remove(mFragmentManager.findFragmentByTag(FRAGMENT_DETAIL_TAG));
    mTransaction.
    mTransaction.commit();
    */

}

@Override
public void onBackStackChanged() {
    // TODO Auto-generated method stub

}

}

I see in my Log that Android calls onDestroyView and onDestroy on my DetailFragment, but somehow it has to store SOMETHING. If I just scroll (which causes OOM Error if I don't recycle convertViews) I don't get errors. Only If I opened details once.

here are the Methods which recycles my bmps:

DETAILS:

public void onDestroyView(){
    LogCat.d(TAG, "onDestroyView");
    LinearLayout iconRow;
    for (int i = 0; i < mIconInflationArea.getChildCount(); i++){
        LogCat.d(TAG, "onDestroyView-> inflationAreaChilds: " + mIconInflationArea.getChildCount());
        iconRow = (LinearLayout)mIconInflationArea.getChildAt(i);
        for (int row = 0; row < iconRow.getChildCount(); row++){
            LogCat.d(TAG, "onDestroyView iconRow childs: " + iconRow.getChildCount());
            View v = iconRow.getChildAt(row);
            if (v instanceof ImageView){
                ImageView image = (ImageView)v;
                Drawable d = image.getDrawable();
                Bitmap bmp = null;
                if (d instanceof SvgDrawable){
                    SvgDrawable svg = (SvgDrawable)d;
                    bmp = svg.getBitmap();
                } else if (d instanceof BitmapDrawable){
                    BitmapDrawable bmpd = (BitmapDrawable)d;
                    bmp = bmpd.getBitmap();
                }
                if (bmp != null){
                    bmp.recycle();
                }
            }
        }
        iconRow = null;
    }
    mIconInflationArea.removeAllViews();
    mMessage = null;
    //System.gc();
    super.onDestroyView();
}

ADAPTER:

private void recycleBmpsFromConvertView(LinearLayout iconArea){
    for (int i = 0; i < iconArea.getChildCount(); i++){
        View v = iconArea.getChildAt(i);
        if (v instanceof LinearLayout){
            LinearLayout row = (LinearLayout)v;
            for (int j = 0; j < row.getChildCount(); j++){
                View candidate = row.getChildAt(j);
                if (candidate instanceof ImageView){
                    ImageView image = (ImageView)candidate;
                    Drawable d = image.getDrawable();
                    Bitmap bmp = null;
                    if (d instanceof SvgDrawable){
                        SvgDrawable svg = (SvgDrawable)d;
                        bmp = svg.getBitmap();
                    } else if (d instanceof BitmapDrawable){
                        BitmapDrawable bmpd = (BitmapDrawable)d;
                        bmp = bmpd.getBitmap();
                    }
                    if (bmp != null){
                        bmp.recycle();
                    }
                }
            }
        }
    }
    iconArea.removeAllViews();
}

Am I right to address that Problem at Fragments API, or is it just something else I miss?

EDIT: It seems to me that I don't have a memory leak. this is what Log tells me:

09-20 17:51:34.578: DEBUG/dalvikvm(11394): GC_EXPLICIT freed 54K, 48% free 4600K/8839K, external 12673K/13427K, paused 93ms
09-20 17:51:54.906: DEBUG/dalvikvm(7904): GC_CONCURRENT freed 608K, 57% free 2902K/6599K, external 1625K/2137K, paused 2ms+7ms
09-20 17:52:00.316: DEBUG/dalvikvm(9634): GC_CONCURRENT freed 550K, 51% free 3242K/6599K, external 1625K/2137K, paused 2ms+7ms
09-20 17:52:12.574: DEBUG/dalvikvm(9634): GC_EXPLICIT freed 352K, 55% free 2998K/6599K, external 1625K/2137K, paused 60ms
09-20 17:52:19.601: DEBUG/dalvikvm(8082): GC_EXPLICIT freed 347K, 53% free 3086K/6535K, external 1625K/2137K, paused 61ms
09-20 17:52:24.609: DEBUG/dalvikvm(7904): GC_EXPLICIT freed 247K, 56% free 2947K/6599K, external 1625K/2137K, paused 64ms
09-20 17:52:53.410: DEBUG/dalvikvm(10578): GC_CONCURRENT freed 540K, 56% free 3007K/6727K, external 1625K/2137K, paused 2ms+9ms
09-20 17:53:05.523: DEBUG/dalvikvm(7904): GC_CONCURRENT freed 591K, 56% free 2952K/6599K, external 1625K/2137K, paused 15ms+2ms
09-20 17:53:35.156: DEBUG/dalvikvm(7904): GC_EXPLICIT freed 259K, 57% free 2895K/6599K, external 1625K/2137K, paused 74ms
09-20 17:53:54.378: DEBUG/dalvikvm(10578): GC_CONCURRENT freed 538K, 56% free 3005K/6727K, external 1625K/2137K, paused 2ms+10ms
09-20 17:54:00.242: DEBUG/dalvikvm(9634): GC_CONCURRENT freed 350K, 52% free 3217K/6599K, external 1625K/2137K, paused 1ms+3ms
09-20 17:54:05.378: DEBUG/dalvikvm(9634): GC_EXPLICIT freed 360K, 55% free 3018K/6599K, external 1625K/2137K, paused 53ms
09-20 17:54:14.785: DEBUG/dalvikvm(8082): GC_EXPLICIT freed 216K, 53% free 3086K/6535K, external 1625K/2137K, paused 58ms
09-20 17:54:16.171: DEBUG/dalvikvm(7904): GC_CONCURRENT freed 574K, 57% free 2899K/6599K, external 1625K/2137K, paused 14ms+2ms
Community
  • 1
  • 1
Rafael T
  • 15,401
  • 15
  • 83
  • 144
  • Check this [outofmemoryerror-bitmap-size-exceeds-vm-budget][1] Hope it helps you. [1]: http://stackoverflow.com/questions/4611822/java-lang-outofmemoryerror-bitmap-size-exceeds-vm-budget – Arun Badole Sep 20 '11 at 13:32
  • doesn't help me. My main question is: is it a problem from Fragement-API, because it was working as I implement it as Activity, or do I just miss something – Rafael T Sep 20 '11 at 14:18
  • It may be that you just didn't notice it. You may have a memory leak in your app and you'll have to discover it. I had much success with watching the logcat output for my app and as I do things in my app, watch to make sure the GC reclaims memory. If you're memory usage continually goes up, then you'll want to use MAT to discover the leaks. – hooked82 Sep 20 '11 at 14:47
  • @hooked82 please look at my Edit: it seems that GC releases my bitmaps from time to time. – Rafael T Sep 20 '11 at 15:58
  • have you enabled hardware acceleration also? If the bitmaps are larger than the native gfx buffer, you'll have problems. – Jon Willis Sep 20 '11 at 16:29
  • @JonWillis huh? where can I enable that? Never heard it before in Android. Although I don't think so. My Icons take up 10% of the screen (at highest). – Rafael T Sep 21 '11 at 12:18

1 Answers1

0

Ok i found out it has nothing do do with Fragments. The bitmaps I use was just too large :)

Rafael T
  • 15,401
  • 15
  • 83
  • 144
  • Hey myself facing same problem. Can you help in this regard please. I will fetch many images from web and currently using lazy loading of images concept. it throws me OutOfMemoryError. Can you help which one used to load many images from web and recycled images – TNR Oct 11 '12 at 10:36