尽管similar question was asked,我有不同的情况:
我的应用主要包含背景Service
。我想开始外部活动并取回结果。
我看到了几个选项:
创建虚拟Activity
并继续引用它以使用其startActivityForResult
。正如我们所知,这会占用大量内存。
使用Broadcast Intents
代替Android的结果基础架构:要求客户端活动在结束前广播其结果。这种打破了这个想法而不是那么高效。
直接使用Instrumentation
- 尝试将startActivityForResult中的代码复制到我的服务中。
使用服务接口 - 序列化并向Intent添加AIDL
连接以启动活动。在这种情况下,活动应该call Service directly而不是提供结果。
第三种方法让我感觉更接近Android,但我不确定是否可以做 - 服务没有它的Instrumentation,默认实现似乎总是返回null。
也许你还有其他想法吗?
答案 0 :(得分:19)
最近在实施具有三条腿授权流程的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.
}
}
}
当您在服务中启动活动时,请创建结果接收器并将其打包到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();
}
}
答案 1 :(得分:4)
我认为选项2是android上最惯用的方式。使用来自startActivityForResult
的{{1}}是同步/阻塞调用,即父活动等待并且在子项完成之前不执行任何操作。当从Activity
工作并与您主要进行异步/非阻塞调用的活动交互时,即服务调出一些工作要做,然后等待信号告诉它可以继续。
如果您使用android local service pattern,那么您可以让您的活动获得Service
的引用,然后在执行其工作后调用特定函数。尝试使用您的选项3将违背框架为您提供的内容。