OutOfMemoryError when loading activities

后端 未结 3 1105
挽巷
挽巷 2021-01-03 09:26

I have a quite simple activity like this :

public class SurvivalActivity extends Activity {
    private static final String KEY_LAYOUT_ID = \"SurvivalLayoutI         


        
相关标签:
3条回答
  • 2021-01-03 10:01

    I'm sorry that the answer of this question wasn't actually possible to have with the elements I gave in my question.

    Indeed, as mentioned in another question here: Why are all my bitmaps upsampled 200%?, I put my pictures in the drawable folder, which, on a xhdpi screen like mine, will cause Android to upsample everything twice (to match xhdpi against mdpi), and will result in a 400% memory usage (twice the width and twice the height so 4 times as many pixels).

    One more thing, since I don't want the user to be able to go back (see the finish() right after the startActivity()), here's what I put in the onPause():

    private void unbindDrawables(View view) {
        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();
        }
    }
    

    This is some code I got here on StackOverflow (for example here: Drawable vs Single reusable Bitmap better with memory?).

    Here are my remarks about this code and why every line is important:

    • The setCallback(null) removes the reference to the activity, so that it can be garbage collected. If you don't do this, all the views will stay in memory.
    • You also need to call it from onPause, because onDestroy is not guaranteed to be called.
    • You may need to cause a garbage collection after this, in order to help the GC understand that some references to objects that were made orphans and that can be GC'd. Just call System.gc().

    This is the resulting onPause code, with the main layout of your activity having the id top_layout:

    @Override
    protected void onPause() {
        super.onPause();
        unbindDrawables(findViewById(R.id.top_layout));
        System.gc();
    }
    
    0 讨论(0)
  • 2021-01-03 10:13

    It might just be that the bitmap you're putting in the ImageView is very large. Here's some things you can try:

    Ditch the xml layout and just inflate and display the problematic ImageView or ImageViews and see if this way you're getting the error.

    Also check each of your images to see what size they actually have. The size they'll take in memory is roughly 4*width*height (in bytes, where width and height are the image's size in pixels).

    Since your Bitmap instances are taking up memory on the heap, I'm imagining you're using Android 3 or above. In these versions that's where Bitmap instances go (just like any other Java instance). In Android 2.x and below, Bitmap instances were allocated in some offheap memory. Knowing this, make sure that that high heap usage you're getting is indeed from the images, and not from some other instances that are created a lot. Try debugging your constructors and see who calls what when the app starts/runs.

    As per Bicou's observations, you might want to manually load your images via BitmapFactory, and in doing so maybe downsample them (via the Options object). Also, try keeping a counter of how much image bytes in memory you total by incrementing with 4*width*height of each image you're actually loading into a Bitmap Object.

    0 讨论(0)
  • 2021-01-03 10:14

    The best way to optimize memory usage with bitmaps in your case is to save a list of your ImageViews make this before call finish() for every ImageView:

    ((BitmapDrawable) myImageView.getDrawable()).getBitmap().recycle();
    myImageView = null;
    
    0 讨论(0)
提交回复
热议问题