. lang。OutOfMemoryError:位图大小超过VM预算—Android JAVA[复制]

时间:2022-01-11 21:19:34

This question already has an answer here:

这个问题已经有了答案:

I have a transparent sprite consists of 10 images which each image has size of 1,000x1,000 px (that means the sprite has size of 10,000x1,000 px). The reason I made quite big resolution because actually I have a full screen animation application and I just want to make sure the image still has a good quality on a big screen phones.

我有一个透明的sprite,由10个图像组成,每个图像的大小为1000x1000像素(也就是说sprite的大小为1万x1000像素)。我之所以做出很大的决定,是因为我有一个全屏动画应用程序,我只是想确保图像在大屏幕手机上仍然具有良好的质量。

So I have class Sprite.java

我有类Sprite.java。

public class Sprite {
    private static final int BMP_ROWS =1;
    private static final int BMP_COLUMNS = 10;
    private int x= 0;
    private int y = 0;
    private GameView gameView;
    private Bitmap bmp;
    private int currentFrame =0;
    private int width;
    private int height;

    public Sprite(GameView gameView, Bitmap bmp){
        this.gameView = gameView;
        this.bmp = bmp;
        this.width = bmp.getWidth() / BMP_COLUMNS;
        this.height = bmp.getHeight() / BMP_ROWS;
    }

    private void update(){
        currentFrame = ++currentFrame % BMP_COLUMNS;
    }

    public void onDraw(Canvas canvas){
        update();
        int srcX = currentFrame*width;
        int srcY = 0 * height;
        Rect src = new Rect(srcX, srcY, srcX+width, srcY+height);
        Rect dst = new Rect(x, y, x+width, y+height);
        canvas.drawBitmap(bmp, src, dst, null); 
    }
}

and this is the code of GameView.java

这是gameview。java的代码。

public class GameView extends SurfaceView {
    private Bitmap bmp;
    private SurfaceHolder holder;
    private GameLoopThread gameLoopThread;
    private Sprite sprite;

    public GameView(Context context) {
        super(context);
        gameLoopThread = new GameLoopThread(this);
        holder = getHolder();
        holder.addCallback(new SurfaceHolder.Callback() {

            @Override
            public void surfaceDestroyed(SurfaceHolder holder) {
                boolean retry = true;
                gameLoopThread.setRunning(false);
                while(retry){
                    try{
                        gameLoopThread.join();
                        retry = false;
                    } catch(InterruptedException e){}
                }
            }

            @Override
            public void surfaceCreated(SurfaceHolder holder) {
                gameLoopThread.setRunning(true);
                gameLoopThread.start();
            }

            @Override
            public void surfaceChanged(SurfaceHolder holder, int format, int width,
                    int height) {
            }
        });
        bmp = BitmapFactory.decodeResource(getResources(), R.drawable.elephant);
        sprite = new Sprite(this, bmp);
    }
    @SuppressLint("WrongCall")
    @Override
    protected void onDraw(Canvas canvas){
        canvas.drawColor(Color.WHITE);
        sprite.onDraw(canvas);
    }
}

However, when I run it on the emulator, I got error

但是,当我在模拟器上运行它时,我出错了。

08-19 11:14:21.103: E/AndroidRuntime(385): FATAL EXCEPTION: main
08-19 11:14:21.103: E/AndroidRuntime(385): java.lang.OutOfMemoryError: bitmap size exceeds VM budget
08-19 11:14:21.103: E/AndroidRuntime(385):  at android.graphics.BitmapFactory.nativeDecodeAsset(Native Method)
08-19 11:14:21.103: E/AndroidRuntime(385):  at android.graphics.BitmapFactory.decodeStream(BitmapFactory.java:460)
08-19 11:14:21.103: E/AndroidRuntime(385):  at android.graphics.BitmapFactory.decodeResourceStream(BitmapFactory.java:336)
08-19 11:14:21.103: E/AndroidRuntime(385):  at android.graphics.BitmapFactory.decodeResource(BitmapFactory.java:359)
08-19 11:14:21.103: E/AndroidRuntime(385):  at android.graphics.BitmapFactory.decodeResource(BitmapFactory.java:385)
08-19 11:14:21.103: E/AndroidRuntime(385):  at binus.killthemall.GameView.<init>(GameView.java:49)
08-19 11:14:21.103: E/AndroidRuntime(385):  at binus.killthemall.MainActivity.onCreate(MainActivity.java:15)
08-19 11:14:21.103: E/AndroidRuntime(385):  at android.app.Instrumentation.callActivityOnCreate(Instrumentation.java:1047)
08-19 11:14:21.103: E/AndroidRuntime(385):  at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:1611)
08-19 11:14:21.103: E/AndroidRuntime(385):  at android.app.ActivityThread.handleLaunchActivity(ActivityThread.java:1663)
08-19 11:14:21.103: E/AndroidRuntime(385):  at android.app.ActivityThread.access$1500(ActivityThread.java:117)
08-19 11:14:21.103: E/AndroidRuntime(385):  at android.app.ActivityThread$H.handleMessage(ActivityThread.java:931)
08-19 11:14:21.103: E/AndroidRuntime(385):  at android.os.Handler.dispatchMessage(Handler.java:99)
08-19 11:14:21.103: E/AndroidRuntime(385):  at android.os.Looper.loop(Looper.java:123)
08-19 11:14:21.103: E/AndroidRuntime(385):  at android.app.ActivityThread.main(ActivityThread.java:3683)
08-19 11:14:21.103: E/AndroidRuntime(385):  at java.lang.reflect.Method.invokeNative(Native Method)
08-19 11:14:21.103: E/AndroidRuntime(385):  at java.lang.reflect.Method.invoke(Method.java:507)
08-19 11:14:21.103: E/AndroidRuntime(385):  at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:839)
08-19 11:14:21.103: E/AndroidRuntime(385):  at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:597)
08-19 11:14:21.103: E/AndroidRuntime(385):  at dalvik.system.NativeStart.main(Native Method)

I don't want to scale my image into smaller size. So, what's wrong and what should I do?

我不想把我的图像缩小到更小的尺寸。那么,怎么了,我该怎么做?

4 个解决方案

#1


0  

Your bitmap size is 80 MBytes. It's really heavy and it's normal that android kills your app with such memory requests. You need to split it somehow, or use Bitmap Options to get image that you actually need.

您的位图大小是80mbytes。它真的很重,android会用这样的内存请求杀死你的应用程序是正常的。您需要以某种方式拆分它,或者使用位图选项来获取实际需要的映像。

#2


0  

An app tends to get about 40ish MB of memory on Android (it varies based on device)- and that includes the size of all resources. So half of that is already gone. You really don't have a lot of memory to work with. You'll be able to load 1 image of that size on most devices. You won't be able to have 2, and if you try to page 1 in and the original out you'll end up spinning up the GC constantly. This approach won't work with images of this size on Android.

一款应用程序可以在Android上获得大约40mb的内存(它根据设备的不同而变化),包括所有资源的大小。其中一半已经消失了。你真的没有太多的记忆要处理。你可以在大多数设备上加载这个大小的图像。你将无法得到2,如果你尝试第1页和第1页,你最终会不断地旋转GC。这种方法无法在Android上使用这种尺寸的图像。

#3


0  

For decoding bitmap use this method and -See this also -Out of memory while creating bitmaps on device

对于解码位图使用这种方法,在设备上创建位图时,也可以看到这一点。

public static Bitmap decodeSampledBitmapFromResource(Resources res, int resId,
int reqWidth, int reqHeight) {

// First decode with inJustDecodeBounds=true to check dimensions
final BitmapFactory.Options options = new BitmapFactory.Options();
options.inJustDecodeBounds = true;
BitmapFactory.decodeResource(res, resId, options);

// Calculate inSampleSize
options.inSampleSize = calculateInSampleSize(options, reqWidth, reqHeight);

 // Decode bitmap with inSampleSize set
 options.inJustDecodeBounds = false;
 return BitmapFactory.decodeResource(res, resId, options);
}


public static int calculateInSampleSize(
    BitmapFactory.Options options, int reqWidth, int reqHeight) {
 // Raw height and width of image
 final int height = options.outHeight;
  final int width = options.outWidth;
int inSampleSize = 1;

if (height > reqHeight || width > reqWidth) {

// Calculate ratios of height and width to requested height and width
final int heightRatio = Math.round((float) height / (float) reqHeight);
    final int widthRatio = Math.round((float) width / (float) reqWidth);

// Choose the smallest ratio as inSampleSize value, this will guarantee
// a final image with both dimensions larger than or equal to the
// requested height and width.
inSampleSize = heightRatio < widthRatio ? heightRatio : widthRatio;
 }

 return inSampleSize;
}

#4


0  

  1. Show a scaled image normally.

    通常显示缩放图像。

  2. Decode and show a portion of bitmap using BitmapRegionDecoder, when zoomed in.

    解码并显示一部分位图使用位图区域解码器,当放大。

  3. Use a disc Cache to store bitmaps.

    使用磁盘缓存存储位图。

#1


0  

Your bitmap size is 80 MBytes. It's really heavy and it's normal that android kills your app with such memory requests. You need to split it somehow, or use Bitmap Options to get image that you actually need.

您的位图大小是80mbytes。它真的很重,android会用这样的内存请求杀死你的应用程序是正常的。您需要以某种方式拆分它,或者使用位图选项来获取实际需要的映像。

#2


0  

An app tends to get about 40ish MB of memory on Android (it varies based on device)- and that includes the size of all resources. So half of that is already gone. You really don't have a lot of memory to work with. You'll be able to load 1 image of that size on most devices. You won't be able to have 2, and if you try to page 1 in and the original out you'll end up spinning up the GC constantly. This approach won't work with images of this size on Android.

一款应用程序可以在Android上获得大约40mb的内存(它根据设备的不同而变化),包括所有资源的大小。其中一半已经消失了。你真的没有太多的记忆要处理。你可以在大多数设备上加载这个大小的图像。你将无法得到2,如果你尝试第1页和第1页,你最终会不断地旋转GC。这种方法无法在Android上使用这种尺寸的图像。

#3


0  

For decoding bitmap use this method and -See this also -Out of memory while creating bitmaps on device

对于解码位图使用这种方法,在设备上创建位图时,也可以看到这一点。

public static Bitmap decodeSampledBitmapFromResource(Resources res, int resId,
int reqWidth, int reqHeight) {

// First decode with inJustDecodeBounds=true to check dimensions
final BitmapFactory.Options options = new BitmapFactory.Options();
options.inJustDecodeBounds = true;
BitmapFactory.decodeResource(res, resId, options);

// Calculate inSampleSize
options.inSampleSize = calculateInSampleSize(options, reqWidth, reqHeight);

 // Decode bitmap with inSampleSize set
 options.inJustDecodeBounds = false;
 return BitmapFactory.decodeResource(res, resId, options);
}


public static int calculateInSampleSize(
    BitmapFactory.Options options, int reqWidth, int reqHeight) {
 // Raw height and width of image
 final int height = options.outHeight;
  final int width = options.outWidth;
int inSampleSize = 1;

if (height > reqHeight || width > reqWidth) {

// Calculate ratios of height and width to requested height and width
final int heightRatio = Math.round((float) height / (float) reqHeight);
    final int widthRatio = Math.round((float) width / (float) reqWidth);

// Choose the smallest ratio as inSampleSize value, this will guarantee
// a final image with both dimensions larger than or equal to the
// requested height and width.
inSampleSize = heightRatio < widthRatio ? heightRatio : widthRatio;
 }

 return inSampleSize;
}

#4


0  

  1. Show a scaled image normally.

    通常显示缩放图像。

  2. Decode and show a portion of bitmap using BitmapRegionDecoder, when zoomed in.

    解码并显示一部分位图使用位图区域解码器,当放大。

  3. Use a disc Cache to store bitmaps.

    使用磁盘缓存存储位图。