Android - 多个活动重启的并发问题

时间:2012-04-25 18:33:54

标签: java android concurrency activity-lifecycle

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

我的应用程序(API 8)目前在onPause中执行“最后机会”用户数据保存,并在onCreate / onStart中检索该数据,这对于单次重启很有效,但如果循环到来则会遇到并发问题背靠背。特别是如果在保存完成之前启动加载,则“最后机会”数据将丢失。

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

并发&线程管理不是我最强的套装,所以我正在寻找能够至少一个保存和解决方案的解决方案。加载任意数量的背靠背重启,没有内存泄漏。由于快速创建 - 破坏循环可能由于非定向原因而发生,仅涉及打破/处理方向变化的想法并不是我真正想要的。

Here's a log file摘录了一些周期,你可以看到活动的创建地点 - 从横向到纵向时被销毁两次。这是我现在所得到的摘录:

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;
}

1 个答案:

答案 0 :(得分:1)

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

它在开发和工作中有效在测试设备上,并没有泄漏活动上下文,所以我们将看到它在野外的作用。

在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);
}

在YourActivity中:

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();
            }
    });
}