持有对已创建活动的引用?

时间:2012-06-09 08:25:06

标签: android android-intent android-activity

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

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

我认为它正试图制作游戏的第二个版本,并且内存不足。我是否应该尝试在菜单中保存游戏活动的副本,如果再次点击“新游戏”,则重新打开它?或者有更简单的方法吗?

我的“新游戏”按钮监听器执行以下操作:( 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);
        }         
    });

logcat是:

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

5 个答案:

答案 0 :(得分:1)

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

我认为你需要在销毁游戏主要活动和进入菜单活动时回收游戏中使用的所有图像。

使用大量图片时,请参阅以下链接以获取良好做法:

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

Strange out of memory issue while loading an image to a Bitmap object

OutofMemoryError: bitmap size exceeds VM budget (Android)

答案 1 :(得分:0)

尝试

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

不喜欢Bundle以便于操作。

编辑: 然后在另一个Activity的onCreate里面:

    Bundle extras = getIntent().getExtras(); 
    if(extras !=null && extras.getInt("CAMPAIGN") == 1){
        newGame();
    }
    else{
        loadGame(extras.getInt("gameId"));
        //or whatever
    }

答案 2 :(得分:0)

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

答案 3 :(得分:0)

您必须在Android Manifest文件中定义活动,这样才能创建单个实例。

<activity
    android:launchMode="singleTask">

答案 4 :(得分:0)

  

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

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

  

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

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

  

或者有更简单的方法吗?

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

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

  2. 确保所有位图都已回收。有时在调整位图大小时,原件会被遗忘。经常是愚蠢的疏忽。看看吧。 :)

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

  4. 在游戏活动结束后添加System.gc()调用。在主要资源发布后,这确实有用。不幸的是,它不能保证。在您的情况下,最好在主菜单的onResume()中。

  5. 一旦你耗尽了所有这些,那么singleTask路线就是实施的简单选择。

    希望这有帮助,

    FuzzicalLogic