Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

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

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();
        }
    }
like image 216
Atinder Avatar asked Sep 12 '12 19:09

Atinder


1 Answers

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.

like image 87
Atinder Avatar answered Sep 20 '22 17:09

Atinder