Один из моих локальных связанных сервисов зависит от другого. Как я могу убедиться, что он не используется, пока его зависимость не будет готова?
Я реализовал части своего приложения для Android в виде двух локально связанных служб, один из которых зависит от другого. (Я использую только bindService()
с ними; никогда startService()
.) Однако, когда я связываю сервис, который имеет зависимость, я получаю ссылку "связанный" и "связанный" с ним до того, как его собственная зависимость будет готова. Это делает вызовы некоторых из его методов неудачными. Как я могу гарантировать, что я не использую свой сервис, пока его зависимые сервисы не подключены? Могу ли я отложить подключение моей службы до тех пор, пока не будут подключены ее собственные зависимости?
Обычно получают только ссылки на связанные сервисы, которые готовы к использованию, потому что onCreate()
а также onBind()
уже были призваны к ним. Тем не менее, когда вы звоните bindService()
в onCreate()
услуги A
за услугу B
, onServiceConnected()
обратный вызов для подключения к B
можно (и в моем случае это!) вызывать после onServiceConnected()
для подключения к A
, По умолчанию все работает в одном и том же (основном интерфейсе) потоке, поэтому вы не можете просто A
"s onBind()
ждать подключения к B
прежде чем он вернется.
Я сделал простое приложение, чтобы продемонстрировать проблему. Вот соответствующие выдержки. Моя деятельность загружает сервис с зависимостью, ServiceA
:
public class MainActivity extends Activity {
private ServiceA serviceA;
private final ServiceConnection connectionA = new ServiceConnection() {
@Override
public void onServiceConnected(ComponentName name, IBinder service) {
serviceA = ((ServiceA.Binder) service).getService();
setGreeting();
}
@Override
public void onServiceDisconnected(ComponentName name) {
serviceA = null;
}
};
protected void setGreeting() {
String greeting = serviceA.getGreeting();
TextView textView = (TextView) findViewById(R.id.greeting);
textView.setText(greeting);
}
@Override
protected void onStart() {
super.onStart();
bindService(new Intent(this, ServiceA.class),
connectionA, Context.BIND_AUTO_CREATE);
}
/* ... */
}
Вот ServiceB
, который ServiceA
зависит от:
public class ServiceB extends Service {
public class Binder extends android.os.Binder {
public ServiceB getService() {
return ServiceB.this;
}
}
@Override
public IBinder onBind(Intent intent) {
return new Binder();
}
public String getGreeting() {
return "Hello";
}
}
И вот ServiceA
:
public class ServiceA extends Service {
public class Binder extends android.os.Binder {
public ServiceA getService() {
return ServiceA.this;
}
}
@Override
public IBinder onBind(Intent intent) {
return new Binder();
}
private ServiceB serviceB;
private final ServiceConnection connectionB = new ServiceConnection() {
@Override
public void onServiceConnected(ComponentName name, IBinder service) {
serviceB = ((Service1.Binder) service).getService();
}
@Override
public void onServiceDisconnected(ComponentName name) {
serviceB = null;
}
};
@Override
public void onCreate() {
bindService(new Intent(this, ServiceB.class),
connectionB, Context.BIND_AUTO_CREATE);
super.onCreate();
}
@Override
public void onDestroy() {
unbindService(connectionB);
super.onDestroy();
}
public String getGreeting() {
return serviceB.getGreeting() + "!";
}
}
Я добавил обе услуги в AndroidManifest.xml
, Когда я запускаю это, serviceB
является null
в призыве к serviceA.getGreeting()
от setGreeting()
, так как connectionB.onServiceConnected()
еще не был вызван.
Есть ли способ, которым я могу сделать connectionA.onServiceConnected()
быть вызванным только после connectionB.onServiceConnected()
был? Или как еще я могу убедиться, что я не использую serviceB
до serviceA.serviceB
был установлен?
Я заметил, что если вместо звонка setGreeting()
прямо в onServiceConnected()
Я post()
это до конца очереди петлителя, проблема, кажется, исчезнет:
@Override
public void onServiceConnected(ComponentName name, IBinder service) {
serviceA = ((ServiceA.Binder) service).getService();
new Handler(getMainLooper()).post(new Runnable() {
@Override
public void run() {
setGreeting();
}
});
}
Я полагаю, это потому, что все onServiceConnected()
звонки, которые должны быть сделаны, уже находятся в очереди петлителя, поэтому, ожидая всех текущих задач, serviceA.serviceB
к тому времени готов setGreeting()
вызывается. Но это кажется мне ненадежным. Это надежно? Есть ли более надежный способ подождать, пока мои услуги не будут готовы?