Android的Java内存不够的异常负荷spritsheets的 [英] Android Java out of memory exception loading spritsheets

查看:324
本文介绍了Android的Java内存不够的异常负荷spritsheets的的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我想你做一个Android设备上的虚拟宠物,但我得到了加载所有spritesheets问题(这些.png文件)。可以装入一定量的薄片withouth的崩溃,但不是全部。当然,这是由于缺乏足够的存储器。这些图像都只有那么650 KB(每个图像都有大约200x6300的分辨率),所以我想我做一些可怕的错误。我的问题:如何把这些图像加载withouth的崩溃是由于一个内存溢出异常

I want do make a virtual pet on a android device, but I got problems loading all the spritesheets (these are .png files). I can load a certain amount of sheets withouth crashing, but not all. Of course this is due to the lack of enough memory. The images are each less then 650 kB (each image has a resolution of roughly 200x6300) , so I guess i'm doing something horrible wrong. My question: "How to load all these images withouth crashing due to an Out of Memory Exception?"

我在一个单独的类加载图像。这个类是负责应用程序需要的所有资源。这里是code我用加载图像。

I load the images in a singleton class. This class is responsible for all the resources the application needs. Here is the code I use to load the images.

public final class ResourceManager {
    public static ResourceManager INSTANCE;
    private int screenWidth, screenHeight;
    private float dpscreenWidth, dpscreenHeight;
    private DisplayMetrics metrics;

    public Bitmap testSheet;
    public Bitmap flapdogBackground;
    public Bitmap flapdog_head;

    public SpriteSheet dogBarking, dogHappy, dogPlayfull, dogSad;

    public ResourceManager(Activity a){
        DisplayMetrics metrics = new DisplayMetrics();
        a.getWindowManager().getDefaultDisplay().getMetrics(metrics);
        this.metrics = metrics;
        screenWidth = metrics.widthPixels;
        screenHeight = metrics.heightPixels;
        dpscreenWidth = screenWidth/metrics.density;
        dpscreenHeight = screenHeight/metrics.density;
        R.drawable.dead_normal);

        initBitmaps(a.getResources());

        flapdogBackground = getResizedBitmap(BitmapFactory.decodeResource(a.getResources(), R.drawable.flapdog_bg), screenWidth, screenHeight);
        int flapdog_width = (int)getPercentageLength(10, true);
        flapdog_head = getResizedBitmap(BitmapFactory.decodeResource(a.getResources(), R.drawable.flapdog_head), flapdog_width, flapdog_width);
        log();
        INSTANCE = this;
    }

    private void initBitmaps(Resources r) {
        Bitmap b;
        double height = getPercentageLength(50, true);
        Log.e("heihgt", "Height is: "+height);
        BitmapFactory.Options options = new BitmapFactory.Options();
        options.inPreferredConfig = Bitmap.Config.RGB_565;
        options.inDither = true;

        b = BitmapFactory.decodeResource(r, R.drawable.dog_happy_f30, options);
        dogHappy = new SpriteSheet(getResizedBitmap(b, (int)(b.getWidth()*(height*30)/b.getHeight()), (int) (height*30)), 30, false);
        b.recycle();
        b = BitmapFactory.decodeResource(r, R.drawable.dog_barking_f30, options);
        dogBarking = new SpriteSheet(getResizedBitmap(b, (int)(b.getWidth()*(height*30)/b.getHeight()), (int) (height*30)), 30, false);
        b.recycle();
        b = BitmapFactory.decodeResource(r, R.drawable.dog_playfull_f30, options);
        dogPlayfull = new SpriteSheet(getResizedBitmap(b, (int)(b.getWidth()*(height*30)/b.getHeight()), (int) (height*30)), 30, false);
        b.recycle();
        b = BitmapFactory.decodeResource(r, R.drawable.dog_sad_f30, options);
        dogSad = new SpriteSheet(getResizedBitmap(b, (int)(b.getWidth()*(height*30)/b.getHeight()), (int) (height*30)), 30, false);
    }

    public float convertDpToPixel(float dp){
        return dp * (metrics.densityDpi / 160f);
    }

    public float convertPixelsToDp(float px){
        return px / (metrics.densityDpi / 160f);
    }

    public double getPercentageLength(double percentage, boolean height){
        if(height){
            return (double)screenHeight*(percentage/100);
        }else{
            return (double)screenWidth*(percentage/100);
        }
    }

    private void log(){
        String s = "Recoursemanager initialized. \nscreenwidth: "+screenWidth + "\nscreenheight: "
                +screenHeight+"\ndpscreenwidth: "+dpscreenWidth+"\ndpscreenheight: "+dpscreenHeight;
        Log.d("RecourceManager", s);
    }

    public static Bitmap getResizedBitmap(Bitmap bm, int newWidth, int newHeight) {
        int width = bm.getWidth();
        int height = bm.getHeight();
        float scaleWidth = ((float) newWidth) / width;
        float scaleHeight = ((float) newHeight) / height;
        Matrix matrix = new Matrix();
        matrix.postScale(scaleWidth, scaleHeight);
        Bitmap resizedBitmap = Bitmap.createBitmap(bm, 0, 0, width, height, matrix, false);
        bm.recycle();
        return resizedBitmap;
    }

    public int getScreenWidth() {
        return screenWidth;
    }

    public int getScreenHeight(){
        return screenHeight;
    }
}

(这似乎有点愚蠢的方式来调整图像,因为Android系统本身提供后的功能加载适当从尺寸图像的MDPI HPDI等文件夹。不知怎的,我不设法得到工作,这就是为什么我想这种做法。)

(this may seem a bit of a stupid way to resize the images, because the android system itself offers the functionallity to load proper sized images from the mdpi hpdi etc. folders. Somehow I don't manage to get that working, that's why I'm trying this approach.)

下面是错误消息:

01-05 19:49:32.363 25711-25711/example.com.virtualpet I/art: Alloc partial concurrent mark sweep GC freed 18(704B) AllocSpace objects, 0(0B) LOS objects, 3% free, 421MB/437MB, paused 366us total 6.317ms
01-05 19:49:32.383 25711-25711/example.com.virtualpet I/art: Alloc concurrent mark sweep GC freed 13(12KB) AllocSpace objects, 0(0B) LOS objects, 3% free, 421MB/437MB, paused 396us total 18.615ms
01-05 19:49:32.383 25711-25711/example.com.virtualpet I/art: Forcing collection of SoftReferences for 140MB allocation
01-05 19:49:32.403 25711-25711/example.com.virtualpet I/art: Alloc concurrent mark sweep GC freed 11(344B) AllocSpace objects, 0(0B) LOS objects, 3% free, 421MB/437MB, paused 396us total 18.066ms
01-05 19:49:32.423 25711-25711/example.com.virtualpet E/art: Throwing OutOfMemoryError "Failed to allocate a 147456012 byte allocation with 16777120 free bytes and 90MB until OOM"
01-05 19:49:32.423 25711-25711/example.com.virtualpet D/AndroidRuntime: Shutting down VM
01-05 19:49:32.443 25711-25711/example.com.virtualpet E/AndroidRuntime: FATAL EXCEPTION: main
Process: example.com.virtualpet, PID: 25711
java.lang.OutOfMemoryError: Failed to allocate a 147456012 byte allocation with 16777120 free bytes and 90MB until OOM
at dalvik.system.VMRuntime.newNonMovableArray(Native Method)
at android.graphics.Bitmap.nativeCreate(Native Method)
at android.graphics.Bitmap.createBitmap(Bitmap.java:939)
at android.graphics.Bitmap.createBitmap(Bitmap.java:912)
at android.graphics.Bitmap.createBitmap(Bitmap.java:843)
at example.com.virtualpet.Util.ResourceManager.getResizedBitmap(ResourceManager.java:111)
at example.com.virtualpet.Util.ResourceManager.initBitmaps(ResourceManager.java:68)
at example.com.virtualpet.Util.ResourceManager.<init>(ResourceManager.java:41)
at example.com.virtualpet.MainActivity.onCreate(MainActivity.java:31)
at android.app.Activity.performCreate(Activity.java:6289)
at android.app.Instrumentation.callActivityOnCreate(Instrumentation.java:1119)
at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:2655)
at android.app.ActivityThread.handleLaunchActivity(ActivityThread.java:2767)
at android.app.ActivityThread.access$900(ActivityThread.java:177)
at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1449)
at android.os.Handler.dispatchMessage(Handler.java:102)
at android.os.Looper.loop(Looper.java:145)
at android.app.ActivityThread.main(ActivityThread.java:5951)
at java.lang.reflect.Method.invoke(Native Method)
at java.lang.reflect.Method.invoke(Method.java:372)
at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:1388)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:1183)

Activity类:

The Activity class:

public class MainActivity extends Activity {
    private DogView view;
    private boolean inGame = false;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        new ResourceManager(this);
    }
}

我读过有关软链接,但也看了这不是一个正确的解决这个问题。另外,bitmap.recycle()似乎并没有帮助对我来说,因为我需要所有的位图。

I've read about softlinks, but also read that isn't a proper solution to this problem. Also the bitmap.recycle() doesn't seem to help In my case, because I need all the bitmaps.

诗。对不起,我的英文不好,我希望你能设法了解我的问题。

Ps. Sorry for the bad english, I hope you manage to understand my problem.

编辑:

忘了提,我已经加入的android:largeheap = TRUE 到Android清单文件。

Forgot to mention I already added android:largeheap=true to the android manifest file.

EDIT2:
在没有需要在同一时刻的所有图像的答案被提及。这是正确的,因此,一个更好的问题将是如何实际使用图像前速只是瞬间高效,加载这些图像。

Was mentioned in the answer that not all the images are needed at the same moment. This is correct, so a better question would be how to load these images efficiently and fast just moments before actually using the image.

解答:
我开始做的,你在我心中的意见多一些思考,并用血统(我需要)来解决:在同一时间不加载的所有图像,但只有当我需要它。这种方法的缺点是,该图像不立刻改变,但一小于一秒钟后。感谢您的时间。

ANSWER: I started to do some more thinking with the comments of you in my mind and came with a descent (for my needs) solution: not loading all the images at the same time, but only when I need it. The drawback of this approach is that the images doesn't change immediatly, but after a less then a second. Thank you for your time.

推荐答案

是狗叫,悲伤,快乐,俏皮在同一时间?
 你需要尝试的你正在尝试做不同的方法。你绝对,如果你不使用,即使他们并不需要在内存中的每一个精灵。

Is the dog barking, sad, happy and playful at the same time? You need to try a different approach of what you are trying to do. You definitely don't need every single sprite in memory if you are not even using them.

这篇关于Android的Java内存不够的异常负荷spritsheets的的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆