从Service线程中调用Android Activity的首选方式是什么?



我目前正在开发一个Android应用程序,具有以下需求:

在Service中启动的工作线程。这个线程做一些处理,需要从主Activity调用,并为同一个Activity提供一些异步响应。

从活动调用服务很容易(IBinder的东西)

我的问题是关于服务回调的正确实现。

我首先要在Activity中添加一个android.os.Handler,并在MyActivity.handleMessage(Message)中处理线程的答案,但这需要我给这个处理程序对服务的引用。那么,当Android操作系统决定销毁/重新创建我的活动,因为一个方向的变化,例如发生了什么?我的活动在服务中(间接)被引用时是否保持活动状态?如果Activity被销毁/重建,服务中的Handler引用会发生什么?

我想我没有使用正确的方法从服务线程回调活动,所以我想知道是否有人可以指出我正确的方法。

TIA

我更喜欢使用LocalBroadcastManager

下面是Activity中的代码示例:

BroadcastReceiver localBroadcastReceiver = new BroadcastReceiver()
{
    @Override
    public void onReceive(Context context, Intent intent)
    {
        Log.d("BroadcastReceiver", "Message received " + intent.getAction());
        Log.d("BroadcaseReceiver", "Received data " + intent.getStringExtra("com.my.package.intent.EXTRA_DATA"));
    }
};
@Override
protected void onStart()
{
    super.onStart();
    final LocalBroadcastManager localBroadcastManager =
        LocalBroadcastManager.getInstance(this);
    final IntentFilter localFilter = new IntentFilter();
    localFilter.addAction("com.my.package.intent.ACTION_NAME_HERE");
    localBroadcastManager.registerReceiver(localBroadcastReceiver, localFilter);
}
@Override
protected void onStop()
{
    super.onStop();
    final LocalBroadcastManager localBroadcastManager =
        LocalBroadcastManager.getInstance(this);
    // Make sure to unregister!!
    localBroadcastManager.unregisterReceiver(localBroadcastReceiver);
}

在你的代码库的其他地方(比如在你的后台线程的完成):

final LocalBroadcastManager localBroadcastManager =
    LocalBroadcastManager.getInstance(context);
final Intent intent = new Intent("com.my.package.intent.ACTION_NAME_HERE")
intent.putExtra("com.my.package.intent.EXTRA_DATA", yourBackgroundData);
localBroadcastManager.sendBroadcast(intent);

当然,您可以使用intent.putExtra添加任何额外的数据或使用多个操作来区分广播消息。

我们通过在Application类中集中所有活动和服务之间的通信来做到这一点。我们扩展Application类,然后在那里拥有绑定到服务并接受回调的方法。在这个体系结构中,ActivityService之间没有直接连接。

这种机制的优点是,你不必担心在活动转换和活动死亡和重新创建期间解除绑定/重新绑定到服务。Application类管理所有这些,它不受活动所做的影响。Application类接收所有回调,您需要在那里编写代码来确定如何处理这些回调。可能您想要在Application类中存储一些数据,然后通知活动有新数据可用,或类似的东西。

另一种方法是让Service广播回调。在这种情况下,服务和活动之间的耦合是松散的,因此您不需要在活动中创建Handler,然后将其传递给Service。活动可以为他们感兴趣的回调注册BroadcastReceiver s,或者您可以在清单中管理它。

一个解决方案,如您所说,是使用MyActivity.handleMessage(Message)。每当您的活动启动(或重新启动)时,您可能会尝试启动服务(您提到的"onBind"内容)。如果服务已经在运行,则不会造成任何损害。绑定工作完成后,告诉Messenger发送回复的服务。

为了确保重启被处理,在onStop中,你需要告诉服务从它的"发送回复的地方列表"中删除该信使,这样它就不会意外地向现在不存在的信使发送消息。当onStart作为重启的一部分被调用时,它将发送现在正确的Messenger。

显然,这要求服务处理此问题,并以某种方式管理场景,其中它有要发送的响应,而没有要发送的Messenger。它要么保留信息,直到Messenger可用,要么丢弃信息,Activity显式地获取所有状态信息,作为它在onStart中完成的绑定的后续操作。

另一种方法是让Activity每隔一段时间(10秒?)在它知道有处理正在进行时轮询Service,看看结果是否可用,然后在所有信息返回后停止轮询。

对于异步服务调用,应该在初始化它时传递回调引用。

回调将由绑定线程执行,这是这种方法的标准。

当然,发起调用的Activity可以依赖于绑定线程在自己的进程中运行的事实。所以从回调回到主/UI线程是很容易的。

因此,如果回调需要在主/UI线程中处理某些东西,它只使用

(new Handler(Looper.getMainLooper()).post()

的优点是它在代码执行的时间点动态地找到主/UI线程。另一方面,这甚至不是必要的,因为主/UI线程没有改变,所以通过视图引用或任何其他你可能在回调中找到它也会工作。

最新更新