2

我有一个透明精灵由 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

4 回答 4

0

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

于 2013-08-19T05:04:41.967 回答
0

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

于 2013-08-19T05:47:12.127 回答
0

对于解码位图,请使用此方法并 - 另请参阅 -在设备上创建位图时内存不足

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;
}
于 2013-08-19T06:30:30.233 回答
0
  1. 正常显示缩放图像。

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

  3. 使用磁盘缓存来存储位图。

于 2013-08-19T06:32:27.807 回答