Android的我怎么等到服务实际上连接?
-
27-09-2019 - |
题
我有一个活动呼叫中IDownloaderService.aidl定义的服务:
public class Downloader extends Activity {
IDownloaderService downloader = null;
// ...
在Downloader.onCreate(束)我试图bindService
Intent serviceIntent = new Intent(this, DownloaderService.class);
if (bindService(serviceIntent, sc, BIND_AUTO_CREATE)) {
// ...
和所述ServiceConnection对象SC内我没有这个
public void onServiceConnected(ComponentName name, IBinder service) {
Log.w("XXX", "onServiceConnected");
downloader = IDownloaderService.Stub.asInterface(service);
// ...
通过添加各种Log.xx我发现,代码后,如果(bindService(...))实际上走之前ServiceConnection.onServiceConnected被称为 - 也就是说,当下载仍然是空 - 这使我陷入困境。在ApiDemos所有样品仅当用户操作触发的呼叫服务避免这一计时问题。但我应该做的到右使用这项服务bindService成功后?我怎么能等待ServiceConnection.onServiceConnected被称为可靠?
另一个问题有关。是否所有的事件处理程序:Activity.onCreate,任何View.onClickListener.onClick,ServiceConnection.onServiceConnected等居然要求在同一个线程(在文档中提到的“主线”)?它们之间有交错,或Android将安排所有事件进入正在处理一个接一个?或者,当究竟是ServiceConnection.onServiceConnected实际上是要叫?一旦Activity.onCreate完成或有时当A.oC仍在运行?
解决方案
我如何可以等待 ServiceConnection.onServiceConnected 被可靠地称为?
您没有。你退出了onCreate()
的(或任何你要绑定),你把你“需要建立连接”代码onServiceConnected()
。
是否所有的事件处理程序: Activity.onCreate,任何 View.onClickListener.onClick, ServiceConnection.onServiceConnected, 等实际调用在同一 螺纹
是
当究竟是 ServiceConnection.onServiceConnected 究竟要叫?上 Activity.onCreate完成或 有时当A.oC仍在运行?
您可能绑定请求甚至不打算的启动的,直到你离开后onCreate()
。因此,onServiceConnected()
会叫你离开onCreate()
后的某个时间。
其他提示
我有同样的问题。我不想把我的绑定的服务相关的代码在onServiceConnected
,不过,因为我想绑定/解除绑定与onStart
和onStop,
,但我不想代码再次每次活动回来前时间运行。我只想要首次创建活动时它运行。
我终于得到了我的onStart()
隧道视野,并使用了布尔值,表明这是否是第一次onServiceConnected
运行与否。这样的话,我可以在unbindService和onStop
再次bindService在不运行的所有启动的东西,每次onStart
。
我结束了这样的事情:
1),得到辅助东西一些范围,我创建一个内部类。至少,丑内部构件从代码的其余部分分离。我需要一个远程服务做的的东西的,因此在类名的字Something
private RemoteSomethingHelper mRemoteSomethingHelper = new RemoteSomethingHelper();
class RemoteSomethingHelper {
//...
}
2)有必要调用远程服务方法两件事情:所述的IBinder并执行该代码。因为我们不知道做哪一个成为第一个已知的,我们储存它们:
private ISomethingService mISomethingService;
private Runnable mActionRunnable;
每个时间我们写入这些域中的一个,我们调用_startActionIfPossible()
:
private void _startActionIfPossible() {
if (mActionRunnable != null && mISomethingService != null) {
mActionRunnable.run();
mActionRunnable = null;
}
}
private void performAction(Runnable r) {
mActionRunnable = r;
_startActionIfPossible();
}
此,当然,假定可运行访问mISomethingService,但是这是用于RemoteSomethingHelper
类的方法中创建可运行真。
这是真的好了ServiceConnection
回调被称为UI线程上一>:如果我们要调用从主线程的服务方法,我们不需要关心同步
ISomethingService
是,当然,通过AIDL定义
3)而不是仅仅将参数传递给方法,我们创建可运行,将调用的方法与这些参数以后,当调用是可能的:
private boolean mServiceBound;
void startSomething(final String arg1) {
// ... starting the service ...
final String arg2 = ...;
performAction(new Runnable() {
@Override
public void run() {
try {
// arg1 and arg2 must be final!
mISomethingService.startSomething(arg1, arg2);
} catch (RemoteException e) {
e.printStackTrace();
}
}
});
}
4)最后,我们得到:
private RemoteSomethingHelper mRemoteSomethingHelper = new RemoteSomethingHelper();
class RemoteSomethingHelper {
private ISomethingService mISomethingService;
private Runnable mActionRunnable;
private boolean mServiceBound;
private void _startActionIfPossible() {
if (mActionRunnable != null && mISomethingService != null) {
mActionRunnable.run();
mActionRunnable = null;
}
}
private ServiceConnection mServiceConnection = new ServiceConnection() {
// the methods on this class are called from the main thread of your process.
@Override
public void onServiceDisconnected(ComponentName name) {
mISomethingService = null;
}
@Override
public void onServiceConnected(ComponentName name, IBinder service) {
mISomethingService = ISomethingService.Stub.asInterface(service);
_startActionIfPossible();
}
}
private void performAction(Runnable r) {
mActionRunnable = r;
_startActionIfPossible();
}
public void startSomething(final String arg1) {
Intent intent = new Intent(context.getApplicationContext(),SomethingService.class);
if (!mServiceBound) {
mServiceBound = context.getApplicationContext().bindService(intent, mServiceConnection, 0);
}
ComponentName cn = context.getApplicationContext().startService(intent);
final String arg2 = ...;
performAction(new Runnable() {
@Override
public void run() {
try {
mISomethingService.startSomething(arg1, arg2);
} catch (RemoteException e) {
e.printStackTrace();
}
}
});
}
}
context
是在我的类的字段;在活动,则可以将其定义为Context context=this;
我并不需要排队的行为;如果你这样做,你可以实现它。
您可能需要在startSomething()的结果的回调;我这样做,但这不是在本代码所示。
我以前那样,唯一不同的是我并没有绑定服务,但刚开始它类似的东西。
我将广播的意图从服务关于它被启动,以通知呼叫方/活性。
*的基本思想是相同与@ 18446744073709551615,但我会分享我的代码。
作为主要问题的答案,
但我应该怎么做才能正确使用这项服务bindService成功后?
<强> [原件的期望(但不工作)] 强>
等到连接象下面服务
@Override
protected void onStart() {
bindService(service, mWebServiceConnection, BIND_AUTO_CREATE);
synchronized (mLock) { mLock.wait(40000); }
// rest of the code continues here, which uses service stub interface
// ...
}
它不会工作,因为在bindService()
和onCreate()/onStart()
两者onServiceConnected()
被称为位于相同主线程即可。
onServiceConnected()
是等待完成之前不会被调用。
<强> [替代溶液] 强>
而不是“等待”,定义已连接服务后自己的可运行被称为和服务连接之后执行此运行的。
实现自定义类ServiceConnection的如下:
public class MyServiceConnection implements ServiceConnection {
private static final String TAG = MyServiceConnection.class.getSimpleName();
private Context mContext = null;
private IMyService mMyService = null;
private ArrayList<Runnable> runnableArrayList;
private Boolean isConnected = false;
public MyServiceConnection(Context context) {
mContext = context;
runnableArrayList = new ArrayList<>();
}
public IMyService getInterface() {
return mMyService;
}
@Override
public void onServiceConnected(ComponentName name, IBinder service) {
Log.v(TAG, "Connected Service: " + name);
mMyService = MyService.Stub.asInterface(service);
isConnected = true;
/* Execute runnables after Service connected */
for (Runnable action : runnableArrayList) {
action.run();
}
runnableArrayList.clear();
}
@Override
public void onServiceDisconnected(ComponentName name) {
try {
mMyService = null;
mContext.unbindService(this);
isConnected = false;
Log.v(TAG, "Disconnected Service: " + name);
} catch(Exception e) {
Log.e(TAG, e.toString());
}
}
public void executeAfterServiceConnected(Runnable action) {
Log.v(TAG, "executeAfterServiceConnected");
if(isConnected) {
Log.v(TAG, "Service already connected, execute now");
action.run();
} else {
// this action will be executed at the end of onServiceConnected method
Log.v(TAG, "Service not connected yet, execute later");
runnableArrayList.add(action);
}
}
}
,然后使用它以下面的方式(在您的活动类或等),
private MyServiceConnection myServiceConnection = null;
@Override
protected void onStart() {
Log.d(TAG, "onStart");
super.onStart();
Intent serviceIntent = new Intent(getApplicationContext(), MyService.class);
startService(serviceIntent);
myServiceConnection = new MyServiceConnection(getApplicationContext());
bindService(serviceIntent, myServiceConnection, BIND_AUTO_CREATE);
// Instead of "wait" here, create callback which will be called after service is connected
myServiceConnection.executeAfterServiceConnected(new Runnable() {
@Override
public void run() {
// Rest of the code comes here.
// This runnable will be executed after service connected, so we can use service stub interface
IMyService myService = myServiceConnection.getInterface();
// ...
}
});
}
这为我工作。但是,可以有更多更好的方法。
我想通了,这些解决方法只值得的努力,并只有当您绑定的服务在不同的过程比你的应用程序的主进程中运行的等待。
有关在同一进程(或应用程序)访问的数据和方法,我结束了实现单类。如果类需要一些方法方面,我泄漏了应用程序上下文的单类。还有就是,当然,它的不良后果,因为它打破了“即时运行”。但是,这是一个整体更好的折衷,我想。