【问题标题】:Android: write to file OnDestroy()Android:写入文件 OnDestroy()
【发布时间】:2012-08-08 05:51:53
【问题描述】:

这是我目前的情况:
日食
Win7
三星 SII(用于测试)

我正在编写一个应用程序,它将在启动时从设备上私有存储的文件中读取,然后,当应用程序的onDestroy() 被调用时,我想写入同一个文件(基本上覆盖)。

我首先尝试用我自己的类扩展应用程序,然后在构造函数中读取和写入该文件并销毁该类,但是,似乎不允许在该类中读取或写入,因为我的应用程序只是崩溃了每次开始时。所以我想了一会儿,辞职在主菜单上做这个,因为这是我唯一不"destroy" (or ActivityName.this.finish();)的活动。但我的程序员大脑希望在应用程序级别而不是活动级别实现这一点。

那么我是否可以从我创建的应用程序类构造函数中读取文件,并写入onDestroy() 中的文件?如果是这样,如何?我的应用程序经常崩溃/甚至无法启动...

这是我使用的代码。这有效地读取一个文件,并将一些字符串存储到全局内存中(请给我“不,不,不”的意思......全局变量对我非常有用),然后在使用值调用 onDestroy() 时覆盖文件在全局变量中(我知道这一点是因为它在活动级别起作用):

CONSTRUCTOR:
super();

    try 
    {
        String origprefs =",0,1-1";

        File f = new File(this.getFilesDir(),FILENAME);

        if(!f.exists())
        {
            FileOutputStream fos2 = new FileOutputStream(f);
            fos2.write(origprefs.getBytes());
            fos2.close();
        }

        FileInputStream fis;
        fis = openFileInput(FILENAME);
        StringBuffer fileContent = new StringBuffer("");

        byte[] buffer = new byte[1024];
        int length;
        while ((length = fis.read(buffer)) != -1) {
            fileContent.append(new String(buffer));
        }
        fis.close();

        origprefs = fileContent.toString();

        //set our globals
        Username = origprefs.split(",")[0];
        Score = origprefs.split(",")[1];
        Stage = origprefs.split(",")[2];

    } 
    catch (IOException e) 
    {
        throw new RuntimeException("Unable to either Read or Write to Match Two file.");
    }

onDestroy:
if(GameRunning)
    {
        try
        {
            FileOutputStream fis;
                fis = openFileOutput(FILENAME, this.MODE_PRIVATE);
                String fileContent = Username + "," + Score + "," + Stage;
                fis.write(fileContent.getBytes());
                fis.close();
        }
        catch(IOException e)
        {
            throw new RuntimeException("Unable to either Read or Write to Match Two file.");
        }
    }

现在,这是相同的过程,只是在 MainMenu 类中减去了一些更改以获得正确的上下文。我只是无法理解为什么当我在应用程序级别执行此操作时这会使我的应用程序崩溃?非常感谢您的帮助!

这里是 logcat 条目 我发现 logcat 很神秘...

08-08 02:03:58.362: E/AndroidRuntime(10360): FATAL EXCEPTION: main
08-08 02:03:58.362: E/AndroidRuntime(10360): java.lang.RuntimeException: Unable to instantiate application maxovrdrv.FirstApp.MatchTwo: java.lang.NullPointerException
08-08 02:03:58.362: E/AndroidRuntime(10360):    at android.app.LoadedApk.makeApplication(LoadedApk.java:466)
08-08 02:03:58.362: E/AndroidRuntime(10360):    at android.app.ActivityThread.handleBindApplication(ActivityThread.java:3268)
08-08 02:03:58.362: E/AndroidRuntime(10360):    at android.app.ActivityThread.access$2200(ActivityThread.java:117)
08-08 02:03:58.362: E/AndroidRuntime(10360):    at android.app.ActivityThread$H.handleMessage(ActivityThread.java:973)
08-08 02:03:58.362: E/AndroidRuntime(10360):    at android.os.Handler.dispatchMessage(Handler.java:99)
08-08 02:03:58.362: E/AndroidRuntime(10360):    at android.os.Looper.loop(Looper.java:130)
08-08 02:03:58.362: E/AndroidRuntime(10360):    at android.app.ActivityThread.main(ActivityThread.java:3691)
08-08 02:03:58.362: E/AndroidRuntime(10360):    at java.lang.reflect.Method.invokeNative(Native Method)
08-08 02:03:58.362: E/AndroidRuntime(10360):    at java.lang.reflect.Method.invoke(Method.java:507)
08-08 02:03:58.362: E/AndroidRuntime(10360):    at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:907)
08-08 02:03:58.362: E/AndroidRuntime(10360):    at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:665)
08-08 02:03:58.362: E/AndroidRuntime(10360):    at dalvik.system.NativeStart.main(Native Method)
08-08 02:03:58.362: E/AndroidRuntime(10360): Caused by: java.lang.NullPointerException
08-08 02:03:58.362: E/AndroidRuntime(10360):    at android.content.ContextWrapper.getFilesDir(ContextWrapper.java:178)
08-08 02:03:58.362: E/AndroidRuntime(10360):    at maxovrdrv.FirstApp.MatchTwo.<init>(MatchTwo.java:26)
08-08 02:03:58.362: E/AndroidRuntime(10360):    at java.lang.Class.newInstanceImpl(Native Method)
08-08 02:03:58.362: E/AndroidRuntime(10360):    at java.lang.Class.newInstance(Class.java:1409)
08-08 02:03:58.362: E/AndroidRuntime(10360):    at android.app.Instrumentation.newApplication(Instrumentation.java:957)
08-08 02:03:58.362: E/AndroidRuntime(10360):    at android.app.Instrumentation.newApplication(Instrumentation.java:942)
08-08 02:03:58.362: E/AndroidRuntime(10360):    at android.app.LoadedApk.makeApplication(LoadedApk.java:461)
08-08 02:03:58.362: E/AndroidRuntime(10360):    ... 11 more

马特

【问题讨论】:

  • 也发布 logcat 输出,如果它崩溃了
  • 可以使用StringBuilder时请不要使用StringBuffer。

标签: android ondestroy writefile


【解决方案1】:

你应该阅读 onDestroy 的文档。你应该使用 onPause 代替。阅读下文了解更多详情

不要指望 this(onDestroy()) 方法被调用作为保存数据的地方!例如,如果 Activity 正在编辑内容提供程序中的数据,则应在 onPause() 或 onSaveInstanceState(Bundle) 中提交这些编辑,

protected void onDestroy ()
Since: API Level 1

在销毁活动之前执行任何最终清理。这可能是因为 Activity 正在完成(有人在其上调用了 finish(),或者因为系统正在临时销毁该 Activity 实例以节省空间。您可以使用 isFinishing() 方法区分这两种情况。

注意:不要指望调用此方法作为保存数据的地方!例如,如果一个活动正在内容提供者中编辑数据,那么这些编辑应该在 onPause() 或 onSaveInstanceState(Bundle) 中提交,而不是在这里。此方法通常用于释放资源,例如与活动关联的线程,以便在其应用程序的其余部分仍在运行时,被破坏的活动不会留下这些东西。在某些情况下,系统会简单地终止 Activity 的宿主进程,而不会在其中调用此方法(或任何其他方法),因此不应使用它来执行打算在进程消失后保留的事情。 派生类必须调用该方法的超类实现。否则,将引发异常。

参考链接:-Android onDestroy

【讨论】:

  • 这很好,但同样,我不是要在活动级别执行此操作,而是在应用级别执行此操作。我确信只有在应用程序死亡时才会调用应用程序的 onDestroy。当您自己关闭它时应该是哪个。
  • 谢谢。我使用了onPause,但必须将其保留在活动中,而不是应用程序中。不是我真正想要的,但它没有任何问题,并且每次用户退出应用程序时都会被解雇。只是希望有一种方法可以在全局/应用程序级别而不是在活动中执行此操作。但是,我重新调整了我的代码以仅使用一个活动来管理游戏的生命周期(例如:关卡进度和屏幕更改都在 MainActivity 类中完成......)所以应该可以工作......我猜...
  • 问题是您不应该在单个活动中进行所有屏幕更改。推荐的是有一个主屏幕,让用户每次想要退出应用程序时都可以进入该屏幕
【解决方案2】:

我认为您选择的数据存储给您带来的问题多于其价值。我不知道有多少情况会依赖即将到来的流程来管理数据流。

根据你的变量名,也许 SharedPreferences 是一个更合适的数据结构? http://developer.android.com/reference/android/content/SharedPreferences.html

如果您坚持使用平面文件,那么我认为您仍然应该使用 contentprovider 管理数据存储。

http://www.vogella.com/articles/AndroidSQLite/article.html

现在 tute 确实使用了 sqlite 支持的内容提供程序。但无论如何你都可以使用平面文件。

无论如何,应用程序崩溃的原因是与数据流时间不同的问题。

【讨论】:

    【解决方案3】:

    PorkAnkit 所说的一切。此外,不要在主 (UI) 线程上执行文件 I/O!除非您保留大量信息,否则我认为SharedPreferences 是要走的路。它非常适合存储重新创建应用状态所需的几十个奇数值。

    【讨论】:

      【解决方案4】:

      查看文档here,似乎没有onDestroy 用于Application 类的方法,所以这似乎使这个想法在那里无法启动。

      我不知道您为什么要尝试重新发明轮子,但我会放弃它并使用其他人都在使用的标准做法......它们是标准做法是有原因的。 :p

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2015-01-14
        相关资源
        最近更新 更多