2010-07-14 89 views
11

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

我看到几个选项:

  1. 创建虚拟Activity,并保持对它的引用使用其startActivityForResult。正如我们所知,这消耗了相当多的内存。

  2. 使用Broadcast Intents,而不是Android的成果基础设施:要求客户活动,在关闭之前播出他们的结果。这种打破想法并不如此高效。

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

  4. 使用服务接口 - 序列化和增加AIDL连接到意向启动的活动。在这种情况下,活动应该call Service directly而不是提供结果。

第三种方法更接近的感觉到Android我,但我不知道是否有可能做的事情 - 服务不具有其仪器仪表,以及默认的实现似乎总是返回null。

也许您有任何其他想法?

+0

它可以用一个简单的黑客来实现,通过使用SharedPreferences的,[SO]( http://stackoverflow.com/a/31461941/4859873) – 2015-07-16 18:46:48

回答

3

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

如果您使用的是android local service pattern,那么您可以让您的活动获得Service的引用,然后在其执行完工作后调用特定的函数。尝试您的选项3将与该框架为您提供的内容相抵触。

+1

感谢您的想法!现在我选择2(更容易实施)和4(更安全/私密,应该更快)。 我不完全同意startActivityForResult是阻塞的(因为它使用回调函数,而不是结果值),而且Instrumentation是在公共API =) 谢谢! – 2010-07-14 21:16:33

+1

我的意思是它不是传统意义上的阻塞(例如阻塞io呼叫)。它阻碍了你使用它的概念性方式。 – Qberticus 2010-07-14 21:53:13

+0

@Qberticus您提供的链接只是指向通用示例页面的链接。 – 2014-08-29 14:58:14

16

实施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. 
     } 

    } 

} 

当你在服务启动的活动,创建一个结果接收机,它包入意图演员:

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

} 
+0

感谢您的解决方案!一件事:RESULT_OK应该是** - 1 **根据Activity.java – Philipp 2016-03-31 21:30:22

+0

好点。我认为在这种情况下可以使用任何值,但最好与平台提供的任何值保持一致。我已经更新了答案。你也可以直接使用Activity.RESULT_OK。 – 2016-04-02 21:10:42

+0

您需要在类MessageReceiver前添加@SuppressLint(“ParcelCreator”),否则它会要求您将CREATOR设置为[ResultReceiver](https://developer.android.com/reference/android/os/) ResultReceiver.html)实现Parcelable。感谢你的回答。 – ArJ 2016-07-27 08:24:42