Warning: file_get_contents(/data/phpspider/zhask/data//catemap/9/java/397.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Android Java内存不足异常加载spritsheets_Java_Android_Bitmap_Out Of Memory - Fatal编程技术网

Android Java内存不足异常加载spritsheets

Android Java内存不足异常加载spritsheets,java,android,bitmap,out-of-memory,Java,Android,Bitmap,Out Of Memory,我确实想在android设备上制作一个虚拟宠物,但我在加载所有SpriteSheet(这些是.png文件)时遇到了问题。我可以加载一定数量的纸张而不会崩溃,但不是全部。当然,这是由于缺乏足够的内存。这些图像都小于650 kB(每个图像的分辨率大约为200x6300),所以我想我做错了什么。我的问题:“如何加载所有这些图像而不因内存不足异常而崩溃?” 我在单例类中加载图像。此类负责应用程序所需的所有资源。下面是我用来加载图像的代码 public final class ResourceManage

我确实想在android设备上制作一个虚拟宠物,但我在加载所有SpriteSheet(这些是.png文件)时遇到了问题。我可以加载一定数量的纸张而不会崩溃,但不是全部。当然,这是由于缺乏足够的内存。这些图像都小于650 kB(每个图像的分辨率大约为200x6300),所以我想我做错了什么。我的问题:“如何加载所有这些图像而不因内存不足异常而崩溃?”

我在单例类中加载图像。此类负责应用程序所需的所有资源。下面是我用来加载图像的代码

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等文件夹加载适当大小图像的功能。不知何故,我无法实现这一点,这就是我尝试这种方法的原因。)

以下是错误消息:

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)
我读过关于软链接的文章,但也读到这不是解决这个问题的正确方法。另外,bitmap.recycle()在我的例子中似乎没有帮助,因为我需要所有的位图

抱歉英语不好,我希望你能理解我的问题

编辑:


忘了提一下我已经在android清单文件中添加了
android:largeheap=true

编辑2: 在回答中提到,并非所有的图像都需要在同一时刻。这是正确的,因此一个更好的问题是如何在实际使用图像之前快速有效地加载这些图像

答复:
我开始在脑海中对你的评论进行更多的思考,并提出了一个下降(针对我的需要)解决方案:不同时加载所有图像,但只在我需要时加载。这种方法的缺点是图像不会立即改变,而是在不到一秒钟的时间内改变。谢谢您的时间。

首先在清单文件中添加此内部应用程序标记
android:largeheap=true
,然后使用
通用图像加载程序
毕加索
获取图像。别担心,这个库管理您的图像,不会导致崩溃。和。

您应该尝试。这将帮助您获得图像的大小,而无需进行缩放,也无需将其加载到内存中

如果设置为true,解码器将返回null(无位图),但输出。。。字段仍将被设置,允许调用者查询位图,而不必为其像素分配内存


这只狗是不是同时在叫、悲伤、快乐和嬉戏?
你需要尝试一种不同的方法来做你想做的事情。如果你甚至不使用它们,你肯定不需要内存中的每一个精灵。

你考虑过使用LibGDX吗

它有精灵表(TextureAtlas)的实现,还有一个构建精灵的工具。这样,您就不必花时间编写自己的spritesheet渲染器/控制器


LibGDX是一个构建游戏的框架,像您这样的虚拟宠物项目听起来是一个很好的候选方案

分配147456012字节分配失败…
好吧,147+MB确实是一大堆内存我考虑过这个框架,但决定不使用它,因为我只需要一个简单的动画。忘了提到我已经在清单中添加了android:largeheap=true,将对其进行编辑。我会在加载程序中尝试。想法是它在这些状态之间切换。没错,所以如果你处于1个状态,你只需要加载来记忆该状态的精灵。不需要加载其他的。然后问题来了,如何实现这一点。
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);
    }
}