我什么时候应该使用 unbindService(),以及如何正确使用它来取消与使用 AIDL 接口的远程服务的绑定?

Jun*_*Lee 6 java service android aidl

我正在编写一个简单的音乐播放器,并且创建了一个播放服务,它实现了一个 AIDL 接口来与客户端绑定,一个是简单的曲目浏览器,另一个是更简单的播放器活动。该服务控制 MediaPlayer 对象,而两个活动使用 ServiceConnections 来获取与该服务的连接。

这包含在两个活动的 onStart() 方法中:

@Override
public void onStart()
{
  super.onStart();
  Intent i = new Intent(this, PureService.class);
  startService(i);
  bindService(i, mConnection, 0);
}
Run Code Online (Sandbox Code Playgroud)

我这样做是为了让服务不会在解绑后立即停止。当然,这实际上并不是问题,因为我的活动根本拒绝与服务解除绑定。每当我的应用程序在这些活动中执行 unbindService 时,unbindService 每次都会抛出 IllegalArgumentException,无一例外(呵呵)。

在 onStop 方法中:

@Override
public void onStop()
{
  super.onStop();

  if (mBound) {
    try {
      unbindService(mConnection);
    } catch (java.lang.IllegalArgumentException e)
    {
      //Print to log or make toast that it failed
    }
  }
  mBound = false;
}
Run Code Online (Sandbox Code Playgroud)

我想知道的是:

  • 我应该在 onStop() 方法中调用 unbindService() 吗?或者根本没有?
  • 我的称呼正确吗?
  • 我启动/绑定服务的方式有什么我应该了解的特殊之处吗?
  • 我是否正在做一些完全错误的事情?我是 Android 编程新手,所以这当然不是不可能的。

提前致谢。

编辑:这是 ServiceConnection 覆盖

public void onServiceConnected(ComponentName className, IBinder service) {
  mBound = true;
  mService = IPureService.Stub.asInterface(service);
}
public void onServiceDisconnected(ComponentName arg0) {
  mBound = false;
}
Run Code Online (Sandbox Code Playgroud)

播放器活动中有一些额外的代码,但它与绑定本身无关。

hac*_*bod 4

首先,除非您确实需要跨进程调用此服务(即从其他 .apk,或者您出于某种原因使用 android:process 将您自己的 .apk 拆分为多个进程),那么我真的建议只放弃使用aidl。它更加复杂,但没有任何好处。服务文档中的“本地服务示例”展示了如何执行此操作:http://developer.android.com/reference/android/app/Service.html

其次,在开始的同时进行绑定强烈表明设计中存在一些基本缺陷。启动服务和绑定到服务在语义上非常不同,因此将根据这些不同的语义在不同的地方完成。也就是说,如果两者都完成了......事实上,这是一种不寻常的情况,您在同一个服务中同时使用启动和绑定。

在用于进行音乐播放的服务的类实现中,它将在主动执行播放时使用 start(因此,当用户不再主动与应用程序的 UI 交互时,其进程不会被系统终止)。当用户进入 UI 时启动服务可能会造成痛苦,因为现在服务的启动/停止状态没有明确定义——它可能会因为正在播放或用户碰巧进入而启动。应用程序的 UI,现在什么时候停止它合适?这会很麻烦。

现在至于何时取消绑定——您只需要确保始终将 unbindService() 与之前的 bindService() 相匹配。从你的代码片段来看,你似乎正在这样做,但其中有一些奇怪的事情,比如 mBound 从未被设置。事实上,如果您始终在 onStart() 中绑定并在 onStop() 中取消绑定,则永远不需要 mBound 来决定是否取消绑定,因为 onStop() 始终在 onStart() 之后调用。

因此,根据您在这里给出的代码,看起来没有问题。不过,如果您遇到异常,那么显然存在异常,因此它可能位于应用程序的其他位置。为了帮助缩小问题范围,您可以在调用bindService()时使用此标志,以便在发生故障时在日志中获取其他信息:http://developer.android.com/reference/android/content/Context.html# BIND_DEBUG_UNBIND