1

在模拟器(ADT v17.0.0)或设备(原始 Droid)上进行方向更改时,我注意到活动有时会经历多个创建-销毁周期。我发现这篇博客文章提到了这个问题,但没有提供解决方案。

我的应用程序(API 8)当前在 onPause 中“最后一次”保存用户数据,并在 onCreate/onStart 中检索该数据,这对于单次重启工作正常,但如果周期恢复,则会出现并发问题-背部。特别是如果在保存完成之前开始加载,“最后机会”数据就会丢失。

我确实阅读了更快的屏幕方向更改 Android 开发者文章,其中提到通过 onRetainNonConfigurationInstance/getLastNonConfigurationInstance 传输对象。我尝试使用 onRetain/getLast... 像一个标志来判断活动是否正在“重新启动”,这很有效,但我仍然有一个主要问题是不知道任何现有的保存/加载操作是否/何时完成。

并发和线程管理不是我最擅长的,所以我正在寻找一种解决方案,它可以在任意数量的背靠背重启中至少进行一次保存和加载,而不会出现内存泄漏。由于非方向原因可能会发生快速创建-销毁周期,因此仅涉及破坏/处理方向更改的想法并不是我真正想要的。

这是一个带有一些周期的日志文件摘录,您可以看到从横向到纵向时活动在哪里被创建-销毁两次。这是我现在得到的摘录:

onPause() {
    file_manager.saveTemporaryPattern(); // writes to OutputStream on UI thread
}

onStart() {
    findViewById (R.id.main_screen).post (new Runnable() {
        file_manager.loadTemporaryPattern(); // reads from InputStream on UI thread
    });

    if (getLastNonConfigurationInstance() != null) {
        // DO SOMETHING HERE?
    }
}

onRetainNonConfigurationInstance() {
    return dummy_object;
}
4

1 回答 1

1

通过将加载/保存调用发送到链接到应用程序上下文而不是活动上下文的处理程序线程来管理解决并发问题。必须在调用中设置加载与保存标记以检查保存->加载->保存模式,避免在横向->纵向方向更改时获得不完整活动生命周期的奇怪行为。

它在开发和测试设备上工作,并且不会泄露活动上下文,所以我们将看看它在野外是如何工作的。

在 YourApp 扩展应用程序:

private Handler fileAccessThread = null;

public void onCreate() {
    super.onCreate();

    if (fileAccessThread == null) {
        fileAccessThread = new Handler();
        token = 0;
    }
}

public void postCallbackFileAccess (int _token, Runnable _callback) {
    switch (_token) {
    case TOKEN_SAVE:
        // Save must follow load, not another save
        if (token == TOKEN_SAVE) { return; }
        token = _token;
        break;

    case TOKEN_LOAD:
//      Have to allow load->load, otherwise data gets lost/deleted
//      if (token == TOKEN_LOAD) { return; }
        token = _token;
        break;
    }

    fileAccessThread.post (_callback);
}

在你的活动中:

protected void onStart() {
    super.onStart();

    ((YourApp) getApplication()).postCallbackFileAccess (
        YourApp.TOKEN_LOAD, new Runnable() {
            @Override
            public void run() {
                file_manager.load();
            }
    });
}

protected void onPause() {
    super.onPause();

    ((YourApp) getApplication()).postCallbackFileAccess (
        YourApp.TOKEN_SAVE, new Runnable() {
            @Override
            public void run() {
                file_manager.save();
            }
    });
}
于 2012-05-31T13:12:52.233 回答