我的设置看起来像这样:
class MyFragment implements SomeEventListener {
Application mAppContext;
boolean mBound;
boolean mDidCallUnbind;
MyIBinder mBinder;
ServiceConnection mConnection = new ServiceConnection() {
@Override
public void onServiceConnected(ComponentName name, IBinder service) {
mBound = true;
mBinder = (MyIBinder) service;
mBinder.getThings();...
}
@Override
public void onServiceDisconnected(ComponentName name) {
mDidCallUnbind = false;
mBound = false;
mBinder = null;
}
};
...
@Override
public void onSomeEvent() {
mAppContext.bindService(...);
}
void unbindService() {
if (mBound && !mDidCallUnbind) {
mDidCallUnbind = true;
mAppContext.unbindService(mConnection);
}
}
@Override
public void onPause() {
unbindService();
super.onPause();
}
}
但是,我仍然会不时看到标题中的错误:java.lang.IllegalArgumentException: Service not registered
被调用时会生成unbindService()
。我错过了一些愚蠢的事情,还是还有更多事情要发生?我应该注意到,现有的这个片段可能不止一个。
修改的
由于似乎没有人在阅读代码,所以让我解释一下。 unbindService()
不会调用Context.unbindService(ServiceConnection)
,除非该服务受到约束(mBound
)且之前尚未调用此onServiceDisconnected(...)
回调可能先前调用unbindService()
。
考虑到这一点,是否有任何情况下Android将解除您的服务绑定,使服务无法绑定,但不会调用onServiceDisconnected,从而使我处于陈旧状态?
另外,我正在使用我的Application上下文来进行初始绑定。假设如下:
@Override
public void onCreate() {
mApplication = getContext().getApplicationContext();
}
答案 0 :(得分:13)
我意识到这个问题已经得到了回答。但我认为有理由去研究人们为什么犯这个错误。
问题在于培训文档。 http://developer.android.com/reference/android/app/Service.html在“活动时间”的https://developer.android.com/guide/components/bound-services.html中显示正确的实施情况。显示非常 INCORRECT 实施。
在' ActivityMessenger'示例onStop()可能在服务实际绑定之前被调用。
这种混淆的原因是他们使用绑定服务布尔值来表示不同示例中的不同内容。 (主要是被称为OR的bindService()实际连接的服务)
在正确的示例中,unbind()基于绑定的布尔值完成,绑定的布尔值表示 bindService()被调用。由于它排队等待主线程执行,因此无论何时(如果有)onServiceConnected()发生,都需要调用unbindService()(因此排队等待执行)。
在其他示例中,例如http://developer.android.com/reference/android/app/Service.html中的那个示例。绑定表示服务实际上已绑定,因此您可以使用它而不会获得NullPointerException。请注意,在此示例中,仍然进行unbindService()调用,并且绑定布尔值不确定是否取消绑定。
答案 1 :(得分:8)
java.lang.IllegalArgumentException: Service not registered
表示在调用unbindService()
时您没有受到服务的约束。
因此,在您onSomeEvent()
unbindService()
之前,onPause()
从未被调用过来
答案 2 :(得分:3)
此异常的另一个可能原因可能是错误的unbindService
调用了Context
。因为服务不仅可以被活动绑定,还可以被Context
继承的其他实例(BroadcastReceivers除外)绑定,甚至可以被其他服务绑定,所以请确保unbindService
由具有以下条件的上下文调用:绑定Service
而不是绑定Service
本身。这将直接产生上面的异常“服务未注册”。
答案 3 :(得分:1)
在我的情况下,我使用Activity Context
调用bindService并尝试使用ApplicationContext
解除绑定。不要这样做。
答案 4 :(得分:0)
我的申请与我的问题完全相同。我不时地得到IllegalArgumentException
。我想这种特殊情况是在服务未绑定且onPause
在 onServiceDisconnected
之前被称为时引起的。所以我会尝试Synchronized
事情以确保正确执行。
答案 5 :(得分:0)
如果在您的Activity中,在bindService()之前调用unbindService(),则将获得此IllegalArgumentException
。
如何避免?
这很简单。如果按此顺序绑定和取消绑定服务,则不需要布尔标志。
解决方案1:
绑定
onStart()
并取消绑定onStop()
Your Activity {
@Override
public void onStart()
{
super.onStart();
bindService(intent, mConnection , Context.BIND_AUTO_CREATE);
}
@Override
public void onStop()
{
super.onStop();
unbindService(mConnection);
}
}
解决方案2:
绑定到onCreate()
,取消绑定到onDestroy()
Your Activity {
@Override
public void onCreate(Bindle sis)
{
super.onCreate(sis);
....
bindService(intent, mConnection , Context.BIND_AUTO_CREATE);
}
@Override
public void onDestroy()
{
super.onDestroy();
unbindService(mConnection);
}
}
Android官方文档suggests,
如果仅在活动可见时需要与服务进行交互,请使用 Solution1 。
如果您希望活动在后台中停止时仍能收到响应,请使用 Solution2 。
答案 6 :(得分:0)
class ServiceBindManager<T>(val context: Context, clazz: Class<T>) {
val TAG: String = "ServiceBindManager"
private val isBound: AtomicBoolean = AtomicBoolean(false)
private var intent: Intent = Intent(context, clazz)
private val connection: ServiceConnection = object : ServiceConnection {
override fun onServiceConnected(name: ComponentName?, service: IBinder?) {
Log.d(TAG, "onServiceConnected: $context")
isBound.set(true)
}
override fun onServiceDisconnected(name: ComponentName?) {
Log.d(TAG, "onServiceDisconnected: $context")
isBound.set(false)
}
override fun onBindingDied(name: ComponentName?) {
isBound.set(false)
}
override fun onNullBinding(name: ComponentName?) {
isBound.set(false)
}
}
fun bindService() {
Log.e(TAG, "bindService: $context")
isBound.set(context.bindService(intent, connection, BIND_AUTO_CREATE))
}
fun unbindService() {
Log.e(TAG, "unbindService: $context")
if (isBound.get()) {
isBound.set(false)
context.unbindService(connection)
}
}
}
用法:
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
serviceBindManager = ServiceBindManager(this@MyActivity, MyService::class.java)
}
override fun onStart() {
super.onStart()
serviceBindManager.bindService()
}
override fun onStop() {
super.onStop()
serviceBindManager.unbindService()
}