关于android:bindService()是否可以阻止?

Can bindService() be made to block?

我有一个使用远程服务的Android应用程序,并使用bindService()进行了绑定,该应用程序是异步的。

在绑定服务之前,该应用程序无用,因此我想简单地等到绑定完成后再开始任何Activity。有没有一种方法可以在调用onCreate()onResume()之前绑定服务?我认为可能有一种方法可以在Application中进行绑定。有什么想法吗?

编辑:

如果在onCreate()中执行此操作。

1
2
bindService(service, mWebServiceConnection, BIND_AUTO_CREATE);
synchronized (mLock) { mLock.wait(40000); }

ServiceConnection.onServiceConnected在40秒钟内未得到调用。显然,如果要绑定服务,必须让onCreate()返回。

所以看来没有办法做我想做的事。

编辑2:
Android如何等待直到实际连接了服务?关于绑定服务时Android中发生的事情,有一些不错的评论。


当我需要等待服务绑定之后才能做其他事情时,我会玩锁。精确地,ServiceConnection拥有一个锁对象,并公开一个waitUntilConnected方法,该方法会阻塞该锁,直到唤醒信号为止。该通知位于onServiceConnected回调中。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
public class MyServiceConnection implements ServiceConnection {

    private volatile boolean connected = false;
    private Object lock = new Object();

    @Override
    public void onServiceConnected(ComponentName name, IBinder binder) {
        connected = true;

        synchronized (lock) {
            lock.notifyAll();
        }
    }

    @Override
    public void onServiceDisconnected(ComponentName name) {
        connected = false;
    }

    public void waitUntilConnected() throws InterruptedException {
        if (!connected) {
            synchronized (lock) {
                lock.wait();
            }
        }
    }

}

因此,例如,如果活动必须等待绑定服务,则它仅调用waitUntilConnected方法。

1
2
3
4
5
6
7
8
9
10
protected void onStart() {
    super.onStart();

    bindService(myServiceIntent, myServiceConnection, Context.BIND_AUTO_CREATE);
    try {
        myServiceConnection.waitUntilConnected();
    } catch (InterruptedException e) {
        e.printStackTrace();
    }
}

作为示例,我将waitUntilConnected方法放在了onStart中,但是必须在另一个线程中调用它。我想听听一种更优雅的方式! :)


您不能具有bindService()块。但是,您的ServiceConnection(bindService的第二个参数)具有回调函数来告诉您何时连接和断开服务,因此您可以使用其他代码块,直到您的onServiceConnected()方法取消阻塞它为止。


似乎有一种方法可以做到这一点。 KeyChain.java和几个Google编写的类使用LinkedBlockingQueue允许同步绑定到服务。

例如,请参见以下名为bind的方法:https://github.com/android/platform_frameworks_base/blob/master/keystore/java/android/security/KeyChain.java

由于使用了阻塞队列,似乎同步返回了服务对象。

不幸的是,如Android文档https://developer.android.com/reference/android/security/KeyChain.html所述,由于从队列中获取元素可能导致某些方法抛出InterruptedException。等待时中断。


Android 10在绑定到提供执行程序的服务时可以引入新的bindService方法签名(可以从执行程序创建)。

1
2
3
4
5
6
7
8
9
10
11
/**
     * Same as {@link #bindService(Intent, ServiceConnection, int)} with executor to control
     * ServiceConnection callbacks.
     * @param executor Callbacks on ServiceConnection will be called on executor. Must use same
     *      instance for the same instance of ServiceConnection.
    */
    public boolean bindService(@RequiresPermission @NonNull Intent service,
            @BindServiceFlags int flags, @NonNull @CallbackExecutor Executor executor,
            @NonNull ServiceConnection conn) {
        throw new RuntimeException("Not implemented. Must override in a subclass.");
    }

查看此答案


bindService()不能被阻止。这样会破坏Service的全部目的。您说您的整个UI都包含该服务的结果。我认为您需要重新考虑您的UI,并使用某种中间表示来填充它,向用户显示应用程序正在收集数据。