1

我正在开发一款安卓游戏,并且刚刚添加了一个主菜单。这是一个单独的活动——所以当有人点击菜单上的“新游戏”按钮时,它会打开一个新的游戏活动意图。

我的问题是如果用户点击“返回”,它会关闭游戏并返回主菜单。当我再次点击“新游戏”时,它崩溃了。

我认为它正在尝试制作游戏的第二个版本,并且内存不足。我是否应该尝试在菜单中保留游戏活动的副本,然后在他们再次点击“新游戏”时重新打开它?或者有没有更简单的方法来做到这一点?

我的“新游戏”按钮侦听器执行以下操作:(IslandGame 是我的主要游戏类 - 捆绑只是告诉它是开始新游戏还是加载以前的游戏,以及从哪个级别开始)

ButtonNewGame.setOnClickListener(new View.OnClickListener() {
        public void onClick(View v) {                 
            Bundle bundle = new Bundle();
            bundle.putString("RESTORE", "NEW"); //in the restore key, say we want a new game
            bundle.putInt("CAMPAIGN", 1); //start in campaign #1

            Intent intent = new Intent(Intent.ACTION_RUN);
            intent.putExtras(bundle);
            intent.setClassName(thisActivity, IslandGame.class.getName());
            startActivity(intent);
        }         
    });

日志是:

06-09 17:42:34.199: E/dalvikvm-heap(239): 147456-byte external allocation too large for this process.
06-09 17:42:34.199: E/(239): VM won't let us allocate 147456 bytes
06-09 17:42:34.209: D/AndroidRuntime(239): Shutting down VM
06-09 17:42:34.209: W/dalvikvm(239): threadid=3: thread exiting with uncaught exception (group=0x4001b188)
06-09 17:42:34.219: E/AndroidRuntime(239): Uncaught handler: thread main exiting due to uncaught exception
06-09 17:42:34.249: E/AndroidRuntime(239): java.lang.RuntimeException: Unable to start activity ComponentInfo{com.dylan.island/com.dylan.island.IslandGame}: android.view.InflateException: Binary XML file line #37: Error inflating class <unknown>
06-09 17:42:34.249: E/AndroidRuntime(239):  at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:2496)
06-09 17:42:34.249: E/AndroidRuntime(239):  at android.app.ActivityThread.handleLaunchActivity(ActivityThread.java:2512)
06-09 17:42:34.249: E/AndroidRuntime(239):  at android.app.ActivityThread.access$2200(ActivityThread.java:119)
06-09 17:42:34.249: E/AndroidRuntime(239):  at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1863)
06-09 17:42:34.249: E/AndroidRuntime(239):  at android.os.Handler.dispatchMessage(Handler.java:99)
06-09 17:42:34.249: E/AndroidRuntime(239):  at android.os.Looper.loop(Looper.java:123)
06-09 17:42:34.249: E/AndroidRuntime(239):  at android.app.ActivityThread.main(ActivityThread.java:4363)
06-09 17:42:34.249: E/AndroidRuntime(239):  at java.lang.reflect.Method.invokeNative(Native Method)
06-09 17:42:34.249: E/AndroidRuntime(239):  at java.lang.reflect.Method.invoke(Method.java:521)
06-09 17:42:34.249: E/AndroidRuntime(239):  at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:860)
06-09 17:42:34.249: E/AndroidRuntime(239):  at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:618)
06-09 17:42:34.249: E/AndroidRuntime(239):  at dalvik.system.NativeStart.main(Native Method)
06-09 17:42:34.249: E/AndroidRuntime(239): Caused by: android.view.InflateException: Binary XML file line #37: Error inflating class <unknown>
06-09 17:42:34.249: E/AndroidRuntime(239):  at android.view.LayoutInflater.createView(LayoutInflater.java:513)
06-09 17:42:34.249: E/AndroidRuntime(239):  at android.view.LayoutInflater.createViewFromTag(LayoutInflater.java:565)
06-09 17:42:34.249: E/AndroidRuntime(239):  at android.view.LayoutInflater.rInflate(LayoutInflater.java:618)
06-09 17:42:34.249: E/AndroidRuntime(239):  at android.view.LayoutInflater.rInflate(LayoutInflater.java:621)
06-09 17:42:34.249: E/AndroidRuntime(239):  at android.view.LayoutInflater.rInflate(LayoutInflater.java:621)
06-09 17:42:34.249: E/AndroidRuntime(239):  at android.view.LayoutInflater.inflate(LayoutInflater.java:407)
06-09 17:42:34.249: E/AndroidRuntime(239):  at android.view.LayoutInflater.inflate(LayoutInflater.java:320)
06-09 17:42:34.249: E/AndroidRuntime(239):  at android.view.LayoutInflater.inflate(LayoutInflater.java:276)
06-09 17:42:34.249: E/AndroidRuntime(239):  at com.android.internal.policy.impl.PhoneWindow.setContentView(PhoneWindow.java:198)
06-09 17:42:34.249: E/AndroidRuntime(239):  at android.app.Activity.setContentView(Activity.java:1622)
06-09 17:42:34.249: E/AndroidRuntime(239):  at com.dylan.island.IslandGame.onCreate(IslandGame.java:76)
06-09 17:42:34.249: E/AndroidRuntime(239):  at android.app.Instrumentation.callActivityOnCreate(Instrumentation.java:1047)
06-09 17:42:34.249: E/AndroidRuntime(239):  at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:2459)
06-09 17:42:34.249: E/AndroidRuntime(239):  ... 11 more
06-09 17:42:34.249: E/AndroidRuntime(239): Caused by: java.lang.reflect.InvocationTargetException
06-09 17:42:34.249: E/AndroidRuntime(239):  at com.dylan.island.IslandView.<init>(IslandView.java:1983)
06-09 17:42:34.249: E/AndroidRuntime(239):  at java.lang.reflect.Constructor.constructNative(Native Method)
06-09 17:42:34.249: E/AndroidRuntime(239):  at java.lang.reflect.Constructor.newInstance(Constructor.java:446)
06-09 17:42:34.249: E/AndroidRuntime(239):  at android.view.LayoutInflater.createView(LayoutInflater.java:500)
06-09 17:42:34.249: E/AndroidRuntime(239):  ... 23 more
06-09 17:42:34.249: E/AndroidRuntime(239): Caused by: java.lang.OutOfMemoryError: bitmap size exceeds VM budget
06-09 17:42:34.249: E/AndroidRuntime(239):  at android.graphics.Bitmap.nativeCreate(Native Method)
06-09 17:42:34.249: E/AndroidRuntime(239):  at android.graphics.Bitmap.createBitmap(Bitmap.java:468)
06-09 17:42:34.249: E/AndroidRuntime(239):  at android.graphics.Bitmap.createBitmap(Bitmap.java:435)
06-09 17:42:34.249: E/AndroidRuntime(239):  at android.graphics.Bitmap.createScaledBitmap(Bitmap.java:340)
06-09 17:42:34.249: E/AndroidRuntime(239):  at android.graphics.BitmapFactory.finishDecode(BitmapFactory.java:488)
06-09 17:42:34.249: E/AndroidRuntime(239):  at android.graphics.BitmapFactory.decodeStream(BitmapFactory.java:462)
06-09 17:42:34.249: E/AndroidRuntime(239):  at android.graphics.BitmapFactory.decodeResourceStream(BitmapFactory.java:323)
06-09 17:42:34.249: E/AndroidRuntime(239):  at android.graphics.BitmapFactory.decodeResource(BitmapFactory.java:346)
06-09 17:42:34.249: E/AndroidRuntime(239):  at android.graphics.BitmapFactory.decodeResource(BitmapFactory.java:372)
06-09 17:42:34.249: E/AndroidRuntime(239):  at com.dylan.island.IslandView$IslandThread.initimages(IslandView.java:435)
06-09 17:42:34.249: E/AndroidRuntime(239):  at com.dylan.island.IslandView$IslandThread.beginLevel(IslandView.java:220)
06-09 17:42:34.249: E/AndroidRuntime(239):  at com.dylan.island.IslandView$IslandThread.<init>(IslandView.java:215)
06-09 17:42:34.249: E/AndroidRuntime(239):  ... 27 more
4

5 回答 5

1

避免java.lang.OutOfMemoryError: bitmap size exceeds VM budget

我认为在破坏游戏主活动并进入菜单活动时,您需要回收游戏中使用的所有图像。

使用大量图像时,请参考以下链接以获得良好做法:

http://android-developers.blogspot.co.uk/2009/01/avoiding-memory-leaks.html

将图像加载到 Bitmap 对象时出现奇怪的内存不足问题

OutofMemoryError:位图大小超出 VM 预算(Android)

于 2012-06-09T08:33:55.847 回答
0

尝试

Intent intent = new Intent(YourCurrentActivity.this, IslandGame.class);
intent.putExtra("Restore", "NEW");
intent.putExtra("CAMPAIGN", 1);
startActivity(intent);

不喜欢 Bunlde 以方便操作。

编辑:然后在其他 Activity 的 onCreate 中:

    Bundle extras = getIntent().getExtras(); 
    if(extras !=null && extras.getInt("CAMPAIGN") == 1){
        newGame();
    }
    else{
        loadGame(extras.getInt("gameId"));
        //or whatever
    }
于 2012-06-09T08:33:30.387 回答
0

您可以覆盖后退按钮的功能以重新启动主要活动并将其设置在您的游戏活动之上,并在返回游戏时执行相同操作。但这显然是一种不好的做法,因为您不确定用户是否会再次点击开始游戏按钮。而是尝试在其 onDestroy 方法上的活动中释放所有使用的资源,并在用户回到它时午餐一个新实例。还尝试最小化您使用的位图的大小。例如尝试 9patches。

于 2012-06-09T08:34:39.153 回答
0

您必须在 Android Manifest 文件中定义活动,以便只能创建一个实例。

<activity
    android:launchMode="singleTask">
于 2012-06-09T08:38:00.747 回答
0

我认为它正在尝试制作游戏的第二个版本,并且内存不足。

你是绝对正确的。如果您正确完成了游戏活动,那么它应该尝试创建第二个版本,因为第一个版本应该已经消失了。

我是否应该尝试在菜单中保留游戏活动的副本,然后在他们再次点击“新游戏”时重新打开它?

一般来说,出于多种原因,这被认为是一种非常糟糕的做法。其中最重要的是由于上下文导致的内存泄漏。

或者有没有更简单的方法来做到这一点?

您可以将游戏活动定义为 singleTask 或 singleInstance。这个(目前)的一个问题是它不是修复内存错误的解决方案。SingleTasks 的编程方式与多实例应用程序不同,还有其他注意事项。由于您的问题在于您首先使用了内存,因此在走这条路之前,我肯定会查看以下内容:

  1. 确保所有资源都已释放。这里特别关注的是对视图的任何静态引用。如果你有它们,请清理它们。

  2. 确保所有位图都被回收。有时在调整位图大小时,会留下原始的。通常是一个愚蠢的疏忽。看看吧。:)

  3. 如果您正在访问文件,请确保它们已关闭。几乎从来没有问题,但总是值得一试。

  4. 在您的游戏活动完成后添加一个 System.gc() 调用。在资源的主要释放之后,这确实可以提供帮助。不幸的是,不能保证。在您的情况下,最好在主菜单的 onResume() 中。

一旦你用尽了所有这些,那么 singleTask 路线只是实现的选择。

希望这可以帮助,

模糊逻辑

于 2012-06-09T08:51:42.610 回答