【问题标题】:Analog of startActivityForResult for Service服务的 startActivityForResult 的模拟
【发布时间】:2011-03-15 22:58:01
【问题描述】:

尽管similar question was asked,我有不同的情况: 我的应用程序主要由背景Service 组成。我想开始外部活动并获得结果。

我看到了几个选项:

  1. 创建虚拟Activity 并保留对它的引用以使用其startActivityForResult。众所周知,这会消耗大量内存。

  2. 使用Broadcast Intents 而不是 Android 的结果基础结构:要求客户端活动在关闭之前广播其结果。这种方式打破了想法,而且性能效率不高。

  3. 直接使用Instrumentation - 尝试将代码从 startActivityForResult 复制到我的服务中。

  4. 使用服务接口 - 序列化并将AIDL 连接添加到 Intent 以启动 Activity。在这种情况下,Activity 应该call Service directly 而不是提供结果。

第三种方法对我来说更接近 Android,但我不确定是否可以这样做 - 服务没有它的 Instrumentation,默认实现似乎总是返回 null。

也许您还有其他想法?

【问题讨论】:

  • 这可以通过一个简单的 hack 来实现,通过使用 SharedPreferences ,SO

标签: android


【解决方案1】:

我最近在使用三足授权流程实现 account authenticators 时一直在考虑这个问题。将结果发送回服务进行处理比在活动中处理它执行得更好。它还提供了更好的关注点分离。

没有那么清楚的记录,但 Android 提供了一种简单的方法,可以使用 ResultReceiver 在任何地方(包括服务)发送和接收结果。

我发现它比传递活动要干净得多,因为这总是伴随着泄露这些活动的风险。此外,调用具体方法也不太灵活。

要在服务中使用ResultReceiver,您需要对其进行子类化并提供一种方法来处理接收到的结果,通常在内部类中:

public class SomeService extends Service {

    /**
     * Code for a successful result, mirrors {@link Activity.RESULT_OK}.
     */
    public static final int RESULT_OK = -1;

    /**
     * Key used in the intent extras for the result receiver.
     */
    public static final String KEY_RECEIVER = "KEY_RECEIVER";

    /**
     * Key used in the result bundle for the message.
     */
    public static final String KEY_MESSAGE = "KEY_MESSAGE";

    // ...

    /**
     * Used by an activity to send a result back to our service.
     */
    class MessageReceiver extends ResultReceiver {

        public MessageReceiver() {
            // Pass in a handler or null if you don't care about the thread
            // on which your code is executed.
            super(null);
        }

        /**
         * Called when there's a result available.
         */
        @Override
        protected void onReceiveResult(int resultCode, Bundle resultData) {
            // Define and handle your own result codes
            if (resultCode != RESULT_OK) {
                return;
            }

            // Let's assume that a successful result includes a message.
            String message = resultData.getString(KEY_MESSAGE);

            // Now you can do something with it.
        }

    }

}

当您在服务中启动 Activity 时,创建一个结果接收器并将其打包到 Intent Extras 中:

/**
 * Starts an activity for retrieving a message.
 */
private void startMessageActivity() {
    Intent intent = new Intent(this, MessageActivity.class);

    // Pack the parcelable receiver into the intent extras so the
    // activity can access it.
    intent.putExtra(KEY_RECEIVER, new MessageReceiver());

    startActivity(intent);
}

最后,在活动中,解包接收器并使用ResultReceiver#send(int, Bundle) 将结果发送回。

您可以随时发送结果,但这里我选择在完成之前发送:

public class MessageActivity extends Activity {

    // ...

    @Override
    public void finish() {
        // Unpack the receiver.
        ResultReceiver receiver =
                getIntent().getParcelableExtra(SomeService.KEY_RECEIVER);

        Bundle resultData = new Bundle();

        resultData.putString(SomeService.KEY_MESSAGE, "Hello world!");

        receiver.send(SomeService.RESULT_OK, resultData);

        super.finish();
    }

}

【讨论】:

  • 感谢您的解决方案!一件事:根据Activity.java,RESULT_OK应该是-1
  • 好点。我认为在这种情况下可以使用任何值,但最好与平台提供的任何值保持一致。我已经更新了答案。您也可以直接使用 Activity.RESULT_OK。
  • 你需要在MessageReceiver类之前添加@SuppressLint("ParcelCreator"),否则它会要求你创建一个CREATOR,因为ResultReceiver实现了Parcelable。感谢您的回答。
【解决方案2】:

我认为选项 2 是 android 上最惯用的方式。从Activity 使用startActivityForResult 是一个同步/阻塞调用,即父活动等待并且在子活动完成之前不做任何事情。当从Service 工作并与您主要执行异步/非阻塞调用的活动进行交互时,即服务调用一些要完成的工作,然后等待一个信号告诉它它可以继续。

如果您正在使用android local service pattern,那么您可以让您的活动获取Service 的引用,然后在它执行完工作后调用特定函数。尝试您的选项 3 将与框架为您提供的内容背道而驰。

【讨论】:

  • 感谢您的意见!现在我在 2(更容易实现)和 4(更安全/私密,应该更快)之间进行选择。我真的不同意 startActivityForResult 是阻塞的(因为它使用回调函数,而不是结果值),而且 Instrumentation 在公共 API =)谢谢!
  • 我的意思是它不是传统意义上的阻塞(例如阻塞 io 调用)。它以您使用它的概念方式阻塞。
  • @Qberticus 您提供的链接只是指向通用示例页面的链接。
猜你喜欢
  • 1970-01-01
  • 2021-02-14
  • 1970-01-01
  • 2021-05-14
  • 2014-09-27
  • 2020-12-21
  • 2018-08-04
  • 2011-02-10
  • 1970-01-01
相关资源
最近更新 更多