次のようなセットアップがあります。
_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();
}
}
_
しかし、時々タイトルにエラーが表示されることがあります。unbindService()
が呼び出されたときに_Java.lang.IllegalArgumentException: Service not registered
_が生成されます。私は愚かな何かを見逃していますか、それとももっと起こっていますか?この同じフラグメントが複数存在する可能性があることに注意してください。
編集
実際に誰もコードを読んでいないようですので、説明させてください。 unbindService()
は、サービスがバインドされていない限り、Context.unbindService(ServiceConnection)
を呼び出しません(mBound
)andonServiceDisconnected(...)
コールバックは、unbindService()
の以前の呼び出しからヒットしました。
そのことを念頭に置いて、Androidがサービスをアンバインドし、サービスがバインドされなくなりますが、onServiceDisconnectedが呼び出されず、古い状態のままになりますか?
また、アプリケーションコンテキストを使用して初期バインディングを実行しています。次のようなものと仮定します。
_@Override
public void onCreate() {
mApplication = getContext().getApplicationContext();
}
_
この質問はすでに回答されています。しかし、なぜ人々がこの間違いを犯しているのかを説明する理由があると思います。
問題は、実際にトレーニングドキュメントにあります。 http://developer.Android.com/reference/Android/app/Service.html は正しい実装を示していますが、 https://developer.Android.com/guide/components/bound -services.html 'ActivityMessenger'のVery[〜#〜] incorrect [〜#〜]実装を示しています。
「ActivityMessenger」の例では、サービスが実際にバインドされる前にonStop()が呼び出される可能性があります。
この混乱の理由は、バインドされたサービスブールを使用して、さまざまな例でさまざまなことを意味しているためです。 (主に、ORは実際に接続されているサービスです)と呼ばれるbindService()でした)
バインドされたブール値に基づいてunbind()が実行される正しい例では、バインドされたブール値はbindService()が呼び出されたことを示します。メインスレッドの実行のためにキューに入れられているため、onServiceConnected()がいつ発生するかに関係なく、unbindService()を呼び出す(実行するためにキューに入れる)必要があります。
http://developer.Android.com/reference/Android/app/Service.html のような他の例では。バインドは、NullPointerExceptionを取得せずに使用できるように、サービスが実際にバインドされていることを示します。この例では、unbindService()呼び出しが引き続き行われ、boundブール値は、アンバインドするかどうかを決定しないことに注意してください。
mIsBound
インスタンスではなく、doBindService()
およびdoUnbindService()
内でServiceConnection
を使用します。
ServiceConnection mConnection = new ServiceConnection() {
@Override
public void onServiceConnected(ComponentName name, IBinder service) {
mBinder = (MyIBinder) service;
}
@Override
public void onServiceDisconnected(ComponentName name) {
mBinder = null;
}
};
...
public void doBindService() {
bindService(new Intent(this, MyService.class),
mConnection, Context.BIND_AUTO_CREATE);
mIsBound = true;
}
public void doUnbindService() {
if (mIsBound) {
unbindService(mConnection);
mIsBound = false;
}
}
これが http://developer.Android.com/reference/Android/app/Service.html で行われる方法です。
_Java.lang.IllegalArgumentException: Service not registered
_は、unbindService()
が呼び出されたときにサービスにバインドされなかったことを意味します。
したがって、あなたの場合、onSomeEvent()
内のunbindService()
を呼び出す前にonPause()
が呼び出されることはありませんでした
この例外の別の考えられる理由は、unbindService
が間違ったContext
によって呼び出されていることです。サービスはアクティビティだけでなく、Context
によって継承された他のインスタンス(BroadcastReceiversを除く)、他のサービスによってもバインドできるため、unbindService
がコンテキストによって呼び出されることを確認してくださいバインドされたService
自体ではなく、Service
をバインドしています。これにより、上記の例外「サービスが登録されていません」が直接発生します。
アクティビティで、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 that
アクティビティがvisibleのときにのみサービスと対話する必要がある場合は、Solution1を使用します。
アクティビティがbackgroundで停止している場合でも応答を受信する場合は、Solution2を使用します。
私のアプリケーションにもまったく同じ問題があります。たまにIllegalArgumentException
を取得します。サービスがバインドされておらず、onPause
がbeforeonServiceDisconnected
と呼ばれているときに、特殊なケースが発生すると思います。そこで、Synchronized
を試して、正しく実行されるようにします。