Один из моих локальных связанных сервисов зависит от другого. Как я могу убедиться, что он не используется, пока его зависимость не будет готова?

Я реализовал части своего приложения для 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() вызывается. Но это кажется мне ненадежным. Это надежно? Есть ли более надежный способ подождать, пока мои услуги не будут готовы?

0 ответов

Другие вопросы по тегам