【问题标题】:startActivityForResult not working properly with launchMode singleInstancestartActivityForResult 无法与 launchMode singleInstance 一起正常工作
【发布时间】:2011-03-22 23:21:07
【问题描述】:

我希望我的应用程序的活动堆栈上的活动只有一个实例。我有几个屏幕是 ListActivities,当 ListActivity 的另一个实例被更改(添加到、编辑、删除等)时,我不想经历更新 ListActivity 的前一个实例中的列表的痛苦和痛苦(或者有什么简单的方法可以做到这一点?)。

注意:我读过 singleTop 会完成这个(虽然如果你点击后退按钮它会破坏 Activity),但它不起作用。我有一个菜单,如果我转到我的收件箱屏幕,然后我转到我的快速列表屏幕,然后我再次转到我的收件箱屏幕,它会创建一个新的收件箱活动。

现在,在我的 ListActivities 上,我已将 launchMode 设置为 singleInstance。问题是:如果我使用 startActivityForResult 启动另一个 Activity,onActivityResult 处理程序会立即触发(在创建新 Activity 之前)。当我在下一个屏幕上执行必要的操作以返回结果时,onActivityResult 处理程序不会触发。

发生了什么事?

这是我触发新 Activity 的方式:

Intent intentLaunchQuickList = new Intent(ActivityMyList.this, ActivityQuickList.class);
startActivityForResult(intentLaunchQuickList, REQUEST_QUICKLIST);

这是我返回结果的方式:

@Override
protected void onListItemClick(ListView l, View v, int position, long id) {
    super.onListItemClick(l, v, position, id);
    QuickListItem qlItem = m_Adapter.getItem(position);
    if (qlItem != null && qlItem.getQLId() != -1) {
        Intent data = new Intent();
        data.putExtra("ql_id", qlItem.getQLId());
        if (getParent() == null) {
            setResult(Activity.RESULT_OK, data);
        }
        else {
            getParent().setResult(Activity.RESULT_OK, data);
        }
    }
    finish();
}

这是我的 onActivityResult 处理程序:

@Override
public void onActivityResult(int requestCode, int resultCode, Intent data) {
    if (requestCode == REQUEST_QUICKLIST) {
        if (resultCode == Activity.RESULT_OK) {
            Bundle extras = data.getExtras();
            if (extras != null) {
                int id = extras.getInt("ql_id");
                if (id > 0) {
                    launchQLItemsThread(id);
                }
            }
        }
    }
}

【问题讨论】:

    标签: android android-activity single-instance


    【解决方案1】:

    来自startActivityForResult 的文档:“例如,如果您正在启动的活动使用 singleTask 启动模式,它将不会在您的任务中运行,因此您将立即收到取消结果。” singleInstance活动也是一样。

    换句话说,如果您想使用 sAFR,您将需要处理多个活动实例。我的建议是将onPause 中的ListActivity 实例的列表状态存储到某个应用程序全局位置(单例或其他),然后从onResume 中加载。然后,即使会创建多个 ListActivity 实例,顶部的实例也会始终在较旧的实例恢复之前更新数据,并且列表将始终对用户显示为最新的。

    请注意,如果您的数据是持久的,那么无论如何您都应该这样做,因为您的整个进程可能会在onPause 调用之后的任何时候被系统杀死,并且如果您还没有在某处保存任何更改当时间回来时,他们很可能在一些——通常是罕见和不可预测的——情况下默默地迷失。在这种情况下,您希望使用本地文件或 SQLite 数据库,而不是持久化到网络。 onPause 需要快速返回,因为用户无法在系统运行时与系统交互,所以保存到本地存储,然后在其他时间同步到网络,可能通过 onPause 启动的服务。

    【讨论】:

    • 感谢您的回复。我明白你想让我做什么,但是,这不会引起问题吗?我显然需要在 onSaveInstanceState 和 onRestoreInstanceState 处理程序中做同样的事情。如果在 onResume 和 onPause 上我从数据库中读取并保存信息,我的应用程序将不必要地从数据库中读取并从 SavedInstanceState 中读取,如果它遇到 onRestoreInstanceState 处理程序,是吗?此外,这真的是 Android 开发人员的常见做法吗?将 ListActivity 数据保存到 ListActivity 的多个实例的单例中?再次感谢您的帮助
    • 另外,你能解释一下为什么 singleTop 不适合我吗?还是我看不懂?
    • SavedInstanceState 仅用于恢复活动的特定实例的状态;用它来保存滚动位置等,而不是列表内容。您想要做的是让您的活动的所有实例共享某种状态,因此如果该状态是持久的,则您希望将该状态放入数据库中,如果它只是来自网络的数据缓存,则希望将该状态放入静态成员中。我根据您所说的建议后者;只需使用数据库来保存您将来仍需要通过网络发送的数据,这样您就不会丢失它。
    • 我想我会将所有内容都放入数据库中。我将需要缓存所有这些数据,以便可以离线使用。我现在确实在某些事情上使用单例。例如,用户登录后,我设置了一个带有用户名、密码、用户 ID 的单例。但是我的很多屏幕的数据都需要离线使用。根据经验,您是否建议我在担心持久数据(和同步多个 Activity 实例)之前让我的 Activity 正常运行?或者我应该在构建应用程序的其余屏幕时继续构建数据库。谢谢
    • 我建议首先将您的数据模型定义为 Java 类,在这些类之上紧密构建活动 UI 实现以驱动设计。数据模型类背后的实际实现可能很简单(不是持久化的东西)并在以后充实。重要的第一步是使数据模型到位以正确驱动 UI。我发现通常最有效的是拥有数据模型类的静态单例实例,每个活动都在 onCreate() 中检索它。然后让这些数据在所有不同的活动实例中传播是微不足道的。
    【解决方案2】:

    我有几个屏幕是 ListActivities,我不想去 通过痛苦和磨难 更新之前的列表 ListActivity 的实例何时 该 ListActivity 的另一个实例 被改变了(或者有一个简单的方法来 这样做?)。

    使用一致的模型。例如,您的数据希望在数据库中。每个ListActivity 在它需要的数据库部分都有一个Cursor。让Cursor 成为“托管光标”(通过startManagingCursor()),您的ListViews 将在onResume() 中自动更新。然后,您可以通过数据库对模型进行更改。

    我有一个菜单,如果我去我的收件箱 屏幕,然后我转到我的快速列表 屏幕,然后我转到我的收件箱 再次屏幕,它会创建一个新的收件箱 活动。

    这就是它应该做的。引用documentation

    “标准”和“单顶”模式 仅在一个方面彼此不同 尊重:每次都有新的意图 对于“标准”活动,新的 类的实例被创建为 回应这个意图。每个实例 处理单一意图。同样,一个 “singleTop”活动的新实例 也可以创建来处理一个新的 意图。但是,如果目标任务 已经有一个现有的实例 位于其堆栈顶部的活动, 该实例将收到新的 意图(在 onNewIntent() 调用中);一种 未创建新实例。 在 其他情况——例如,如果 的现有实例 “singleTop”活动在目标中 任务,但不在栈顶, 或者如果它在堆栈的顶部,但是 不在目标任务中——一个新的 实例将被创建并推送 在堆栈上。

    (加粗表示强调)

    现在,在我的 ListActivities 上,我已将 launchMode 设置为 singleInstance。

    请不要这样做。

    【讨论】:

    • 感谢您的回复。您能否向我提供一些有关托管游标和数据库的有用信息的链接?我还没有在 Android 应用程序中实现数据库。
    • 目前(我上周开始使用此应用程序,这是我的第一个应用程序)我只是从我的 Web 服务中提取数据并填充列表。显然,创建 Activity 的新实例将需要再次从 Web 服务中提取数据。这就是我开始使用 singleInstance 的原因。我理解你所说的背后的逻辑。我还没有实现类似的东西;所以一些资源会有所帮助。再次感谢
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2017-12-14
    • 2020-08-19
    • 2013-02-06
    • 2019-02-02
    • 2021-10-15
    • 2016-07-05
    • 2016-09-13
    相关资源
    最近更新 更多