Unbinding drawables onPause() causing unresponsive back navigation and skipping this step cause memory overflow
Asked Answered
A

2

6

I am using an image to set as the background for all my activities but it was causing a memory overflow issue and crash the app. Now I am unbinding my drawables on pause() and on Destroy() in my activity and now it shows blank screen on pressing back button. So how can I avoid this without using extra memory.

    protected void onPause(){
    super.onPause();
    unbindDrawables(findViewById(R.id.login_root));
}

protected void onDestroy() {
        unbindDrawables(findViewById(R.id.login_root));
        super.onDestroy();
      }

private void unbindDrawables(View view) {
    System.gc();
    Runtime.getRuntime().gc();
    if (view.getBackground() != null) {
    view.getBackground().setCallback(null);
    }
    if (view instanceof ViewGroup) {
        for (int i = 0; i < ((ViewGroup) view).getChildCount(); i++) {
        unbindDrawables(((ViewGroup) view).getChildAt(i));
        }
    ((ViewGroup) view).removeAllViews();
    }

Initially I was inflating my layout using android:background="@drawable/" which always caused memory overflow error saying that VM won't let us allocate 10MB (app.) Now I am getting a bitmap from that drawable without scaling down and binding it on runtime.Now it says VM won't let us allocate 5MB (app.) without using unbindDrawables(..) Obviously the quality of background image which is shown has decreased but I am not able to understand that if I am using a png file of 13KB, how does JVM requires 5 or 10MB space to process the request ?

I have shift my layout statements from onCreate() to onResume() method but the application again runs out of memory on pressing back button.

public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
    }

  protected void onResume(){
        setContentView(R.layout.home);
        Bitmap bmp;
        ImageView background = (ImageView)findViewById(R.id.iv_home_background);
        InputStream is = getResources().openRawResource(R.drawable.background);
        bmp = BitmapFactory.decodeStream(is);
        background.setImageBitmap(bmp);

         super.onResume();
    }

 protected void onPause(){
        super.onPause();
        unbindDrawables(findViewById(R.id.home_root));
    }


 private void unbindDrawables(View view) {
        System.gc();
        Runtime.getRuntime().gc();
        if (view.getBackground() != null) {
        view.getBackground().setCallback(null);
        }
        if (view instanceof ViewGroup) {
            for (int i = 0; i < ((ViewGroup) view).getChildCount(); i++) {
            unbindDrawables(((ViewGroup) view).getChildAt(i));
            }
        ((ViewGroup) view).removeAllViews();
        }
    }
Amazed answered 12/9, 2012 at 19:34 Comment(5)
Remember that if onDestroy() is called, onPause() is called before as well.Fredericksburg
unbind only in onPause() as @JohnSatriano stated. But still, do show us your onResume functionAntisocial
I did not override my on Resume function. I have absolutely no idea what to do there.Amazed
I have made the changes in my onResume() code but its crashing my app.Amazed
A PNG image is compressed but for to be shown, the system must hold it in memory uncompressed, so it needs 3 or -- with transparency -- 4 bytes per pixel. That's 1.2 MB for an image of 640x480 pixels.Tymon
A
1

I have found a work around for this problem. Now I am scaling my bitmaps at runtime to a very small size and then storing them in internal storage. The program calls the scaled bitmaps from the storage at runtime and if its not present there, it calls it from drawable folder, scale it, write it to storage and then bind it to the view. In this way there is no need to call unbindDrawables method at any point of time and the application remains responsive throughout. My only concern right now is the quality of bitmaps, I think I need to play around with the scaling size to find out the least possible size with maximum quality.

Amazed answered 17/9, 2012 at 9:17 Comment(0)
T
0

You are calling GC for each sub view. Try calling it only once when all the unbinds are done.

unbindDrawables(findViewById(R.id.login_root));
System.gc();

GC is a heavy load and it is useless to call it too often. in fact, if there are no leaks it should be nesesary at all.

Also have in mind that png file sizes have nothing to do with a bitmap on memory. Here is more info on that http://developer.android.com/training/displaying-bitmaps/index.html

Thromboplastic answered 16/9, 2013 at 13:54 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.