我有一个使用远程服务的Android应用程序,并使用bindService()
绑定它,这是异步的。
在服务绑定之前,应用程序是无用的,所以我想等到绑定完成后再启动任何Activity。有没有办法在调用onCreate()
或onResume()
之前绑定服务?我认为可能有办法在Application
中进行绑定。有什么想法吗?
编辑:
如果在onCreate()
我这样做。
bindService(service, mWebServiceConnection, BIND_AUTO_CREATE);
synchronized (mLock) { mLock.wait(40000); }
ServiceConnection.onServiceConnected在40秒内未被调用。很明显,如果我希望服务绑定,我必须让onCreate()返回。
所以似乎没有办法做我想做的事。
编辑2: Android how do I wait until a service is actually connected?对绑定服务时Android中发生的事情有一些很好的评论。
答案 0 :(得分:7)
当我需要在做其他事情之前等待服务被绑定时,我会玩锁。确切地说,ServiceConnection
拥有一个锁定对象并暴露一个阻塞锁定的waitUntilConnected
方法,直到唤醒信号。该通知位于onServiceConnected
回调中。
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
方法。
protected void onStart() {
super.onStart();
bindService(myServiceIntent, myServiceConnection, Context.BIND_AUTO_CREATE);
try {
myServiceConnection.waitUntilConnected();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
我将waitUntilConnected
方法放在onStart
中仅作为示例,但必须在不同的线程中调用。我想听一个更优雅的方式! :)
答案 1 :(得分:6)
你不能拥有bindService()块。但是,您的ServiceConnection(bindService的第二个参数)具有回调函数,可以告诉您服务何时连接和断开连接,因此您可以使用其他代码块,直到您的onServiceConnected()方法取消阻止它。
答案 2 :(得分:4)
似乎有办法做到这一点。 KeyChain.java
和几个Google编写的类使用LinkedBlockingQueue
来同步绑定到服务。
bind
的方法
由于使用阻塞队列,它似乎同步返回服务对象。
不幸的是,正如Android docs https://developer.android.com/reference/android/security/KeyChain.html所述,由于队列中的元素在等待时可能会被中断,因此某些方法会抛出InterruptedException
。
答案 3 :(得分:0)
bindService()
无法阻止。这种做法挫败了Service
的整个目的。您说整个UI包含来自服务的结果。我认为您需要重新考虑您的UI并使用某种中间表示填充它,向用户显示应用正在收集数据。
答案 4 :(得分:0)
Android 10 在绑定到服务以提供 Executor(可以从 Executor 创建)时引入了新的 bindService 方法签名。
/**
* 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.");
}
看到这个Answer