startActivityForResult 无法与 launchMode singleInstance 正常工作

发布于 2024-09-12 09:45:24 字数 1790 浏览 3 评论 0原文

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

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

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

到底是怎么回事?

这是我如何触发新活动:

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

I'd like Activities on my application's Activity stack to only have one instance. I have several screens which are ListActivities and I'd like to not go through the pain and suffering of updating the lists in a previous instance of the ListActivity when another instance of that ListActivity is changed (added to, edited, removed from, etc) (or is there an easy way to do this?).

Note: I've read that singleTop will accomplish this (though it destroys the Activity if you hit the back button), but it does not work. I have a menu and if I go to my Inbox screen, then I go to my QuickList screen, and then I go to my Inbox screen again, it creates a new Inbox Activity.

Right now, on my ListActivities, I have launchMode set to singleInstance. The problem is: If I launch another Activity using startActivityForResult, the onActivityResult handler fires right away (before the new Activity is created). When I perform the necessary action on the next screen to return the result, the onActivityResult handler does not fire.

What is going on?

Here is how I fire the new Activity:

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

Here is how I return the result:

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

Here is my onActivityResult handler:

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

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(2

つ低調成傷 2024-09-19 09:45:24

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

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

请注意,如果您的数据是持久性的,那么无论如何您都应该这样做,因为在 onPause 调用之后,您的整个进程可能会被系统随时终止,并且如果您尚未保存任何更改当他们返回时,他们可能会在某些(通常是罕见且不可预测的)情况下悄然迷失。在这种情况下,您希望使用本地文件或 SQLite 数据库,而不是持久保存到网络。 onPause 需要快速返回,因为用户在系统运行时无法与系统交互,因此保存到本地存储,然后在其他时间同步到网络,可能通过 onPause

From the documentation of startActivityForResult: "For example, if the activity you are launching uses the singleTask launch mode, it will not run in your task and thus you will immediately receive a cancel result." singleInstance activities are the same way.

In other words, if you want to use sAFR, you will need to handle multiple activity instances. What I would advise is storing the list state for your ListActivity instances in onPause to some app-global spot (a singleton or whatever), and loading from there in onResume. Then, even if multiple ListActivity instances will get created, the top one will always update the data before the older ones get resumed, and the lists will always appear current to the user.

Note that you should be doing that anyway if your data is meant to be persistent, because your whole process can be killed by the system any time after an onPause call, and if you haven't saved any changes somewhere by the time that returns, they are liable to get silently lost under some -- often rare and unpredictable -- circumstances. In this case you want to be using local files or SQLite databases, not persisting to the network. onPause needs to return quickly because the user can't interact with the system while it's running, so save to local storage and then sync to the network at some other time, perhaps via a service launched by onPause.

梦在深巷 2024-09-19 09:45:24

我有几个屏幕
列出活动,但我不想去
通过痛苦和磨难
更新之前的列表
ListActivity 的实例,当
该 ListActivity 的另一个实例
被改变了(或者有没有一个简单的方法
这样做吗?)。

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

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

这就是它应该做的。引用文档

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

(添加粗体以强调)

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

请不要这样做。

I have several screens which are
ListActivities and I'd like to not go
through the pain and suffering of
updating the lists in a previous
instance of the ListActivity when
another instance of that ListActivity
is changed (or is there an easy way to
do this?).

Use a consistent model. For example, your data is hopefully in a database. Each ListActivity has a Cursor on the portion of the database it needs. Have that Cursor be a "managed Cursor" (via startManagingCursor()), and your ListViews will update automatically in onResume(). You then make your changes to your model via the database.

I have a menu and if I go to my Inbox
screen, then I go to my QuickList
screen, and then I go to my Inbox
screen again, it creates a new Inbox
Activity.

That's what it is supposed to do. Quoting the documentation:

The "standard" and "singleTop" modes
differ from each other in just one
respect: Every time there's new intent
for a "standard" activity, a new
instance of the class is created to
respond to that intent. Each instance
handles a single intent. Similarly, a
new instance of a "singleTop" activity
may also be created to handle a new
intent. However, if the target task
already has an existing instance of
the activity at the top of its stack,
that instance will receive the new
intent (in an onNewIntent() call); a
new instance is not created. In
other circumstances — for example, if
an existing instance of the
"singleTop" activity is in the target
task, but not at the top of the stack,
or if it's at the top of a stack, but
not in the target task — a new
instance would be created and pushed
on the stack.

(boldface added for emphasis)

Right now, on my ListActivities, I have launchMode set to singleInstance.

Please do not do this.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文