java.lang.OutOfMemoryError:位图大小超过VM预算 - Android JAVA

时间:2013-08-19 04:49:33

标签: java android bitmap android-canvas sprite

我有一个透明的精灵由10个图像组成,每个图像的大小为1,000x1,000像素(这意味着精灵的大小为10,000x1,000像素)。我之所以做出相当大的分辨率,是因为实际上我有一个全屏幕动画应用程序而且我只是想确保图像在大屏幕手机上仍然具有良好的质量。

所以我有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); 
    }
}

这是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);
    }
}

但是,当我在模拟器上运行它时,我收到了错误

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)

我不想将图像缩放到更小的尺寸。那么,什么是错的,我应该怎么做?

4 个答案:

答案 0 :(得分:0)

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

答案 1 :(得分:0)

Android上的应用程序往往会获得大约40 GB的内存(因设备而异) - 包括所有资源的大小。所以有一半已经消失了。你真的没有很多内存可以使用。您将能够在大多数设备上加载1个该大小的图像。您将无法拥有2,如果您尝试进入第1页并且原始输出,您将最终不断地启动GC。这种方法不适用于Android上这种尺寸的图像。

答案 2 :(得分:0)

对于解码位图,请使用此方法,并参见 - 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;
}

答案 3 :(得分:0)

  1. 正常显示缩放图像。

  2. 放大时使用BitmapRegionDecoder解码并显示部分位图。

  3. 使用disc Cache存储位图。

相关问题