问题描述
我目前在我的应用中使用 2 项服务:
I am currently using 2 services in my app:
1:LocationService,主要是尝试本地化用户,目标是仅在应用处于前台时才保持活动状态.
1: LocationService, basically trying to localize the user, and aims to stay alive only when the app is on foreground.
2:XmppService,它初始化与 xmpp 服务器的连接、接收消息、发送消息、注销...并旨在保持活动状态直到用户注销.
2: XmppService, which init the connection with the xmpp server, receive messages, send it, logout ... and aims to stay alive until the user logout.
我已经阅读了很多文档,但我无法说清楚.
I've been reading quite a lot of documentation, but I just can't make it clear.
当我尝试存储 LocationServiceBinder 的引用时,我遇到了泄漏,它用于调用我的服务函数(使用 AIDL 接口).Xmpp 也一样.当我解除绑定时,有时会出现 ANR(这似乎与我的绑定/解除绑定异常完成的事实有关,onResume、onRestart ...).
I'm having Leaks when I try to store reference of LocationServiceBinder, which is used to call my service functions (using AIDL interfaces). Same for Xmpp. When I unbind, I get sometimes ANR (which look like to be linked with the fact that my bind/unbind are weirdly done, onResume, onRestart ...).
所有系统都在工作,但我确信这不是正确的做法,我很乐意跟随有经验的人回到部队的右侧!:)
All the system is working, but I'm sure it is not the right way to do it, and please I would love to follow experienced people to come back in the right side of the force ! :)
干杯
更新
我的位置服务在应用启动时绑定,以尽可能快地获取用户的位置:
My Location Service is bind at the app launch to get as fast as possible the user's position :
if(callConnectService == null) {
callConnectService = new ServiceConnection() {
public void onServiceConnected(ComponentName name, IBinder binder) {
locationServiceBinder = LocationServiceBinder.Stub.asInterface(binder);
try {
global.setLocationBinder(locationServiceBinder);
global.getLocationBinder().startLocationListener();
} catch (Exception e){
Log.e(TAG, "Service binder ERROR");
}
}
public void onServiceDisconnected(ComponentName name) {
locationServiceBinder = null;
}
};
}
/* Launch Service */
aimConServ = new Intent(this, LocationService.class);
boolean bound = bindService(aimConServ,callConnectService,BIND_AUTO_CREATE);
我的 Xmpp 服务在用户登录时启动:
My Xmpp Service is launched when the user log in :
callConnectService = new ServiceConnection() {
callConnectService = new ServiceConnection() {
public void onServiceConnected(ComponentName name, IBinder binder) {
try {
Log.d(TAG, "[XMPP_INIT] Complete.");
global.setServiceBinder(ConnectionServiceBinder.Stub.asInterface(binder));
//Connect to XMPP chat
global.getServiceBinder().connect();
} catch (Exception e){
Log.e(TAG, "Service binder ERROR ");
e.printStackTrace();
}
}
public void onServiceDisconnected(ComponentName name) {
Log.e(TAG, "Service binder disconnection ");
}
};
/* Launch Service */
Intent aimConServ = new Intent(MMWelcomeProfile.this, XmppService.class);
bound = bindService(aimConServ,callConnectService,Context.BIND_AUTO_CREATE);
并在每个 Activity 上取消绑定:
and unbind on each Activity :
if (callConnectService != null){
unbindService(callConnectService);
callConnectService = null;
}
推荐答案
在谷歌官方开发指南中并没有详细记载,Context.bindService() 实际上是一个异步调用.这就是为什么 ServiceConnection.onServiceConnected() 被用作回调方法的原因,意味着不会立即发生.
It hasn't been well-documented in Google's official dev guide, Context.bindService() is actually an asynchronous call. This is the reason why ServiceConnection.onServiceConnected() is used as a callback method, means not happened immediately.
public class MyActivity extends Activity {
private MyServiceBinder myServiceBinder;
protected ServiceConnection myServiceConnection = new ServiceConnection() {
public void onServiceConnected(ComponentName className, IBinder service) {
myServiceBinder = (MyServiceBinderImpl) service;
}
... ...
}
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
// bindService() is an asynchronous call. myServiceBinder is resoloved in onServiceConnected()
bindService(new Intent(this, MyService.class),myServiceConnection, Context.BIND_AUTO_CREATE);
// You will get a null point reference here, if you try to use MyServiceBinder immediately.
MyServiceBinder.doSomething(); // <-- not yet resolved so Null point reference here
}
}
解决方法是在 myServiceConnection.onServiceConnected() 中调用 MyServiceBinder.doSomething(),或者通过一些用户交互(例如按钮单击)执行 MyServiceBinder.doSomething(),因为在调用 bindService() 之后和系统获取之前的滞后myServiceBinder 的引用很快.只要你不立即使用它就可以了.
A workaround is call MyServiceBinder.doSomething() in myServiceConnection.onServiceConnected(), or perform MyServiceBinder.doSomething() by some user interaction (e.g. button click), as the lag after you call bindService() and before system get a reference of myServiceBinder is quite soon. as long as you are not using it immediately, you should be just fine.
查看这个 SO 问题CommonsWare 的答案了解更多详情.
Check out this SO question CommonsWare's answer for more details.
这篇关于Android 上服务的良好做法的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持编程学习网!