【问题标题】:Good practices for services on AndroidAndroid 服务的良好实践
【发布时间】:2012-01-10 14:58:16
【问题描述】:

我目前在我的应用中使用 2 项服务:

1:LocationService,主要是尝试本地化用户,目的是仅在应用处于前台时保持活动状态。

2:XmppService,它初始化与 xmpp 服务器的连接、接收消息、发送消息、注销...并旨在保持活动状态直到用户注销。

我已经阅读了很多文档,但我无法说清楚。

当我尝试存储 LocationServiceBinder 的引用时,我遇到了泄漏,它用于调用我的服务函数(使用 AIDL 接口 )。 Xmpp 也一样。当我解除绑定时,有时会出现 ANR(这似乎与我的绑定/解除绑定异常完成的事实有关,onResume、onRestart ...)。

所有系统都在工作,但我确信这不是正确的做法,我很乐意跟随有经验的人回到部队的右侧! :)

干杯

更新

我的位置服务在应用启动时绑定,以尽可能快地获取用户的位置:

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 服务在用户登录时启动:

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 上取消绑定:

if (callConnectService != null){
        unbindService(callConnectService);
        callConnectService = null;
    }

【问题讨论】:

  • 发布一些代码 sn-p 在您有问题的活动中的绑定/取消绑定服务可能会帮助其他人找到您的问题。
  • 已更新,只是添加了一些代码

标签: android service geolocation xmpp


【解决方案1】:

在 Google 的官方开发指南中没有详细记录,Context.bindService() 实际上是一个异步调用。这就是为什么 ServiceConnection.onServiceConnected() 被用作回调方法的原因,意味着不会立即发生。

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 的引用很快。只要你不立即使用它,你应该没问题。

查看这个 SO 问题CommonsWare's answer 了解更多详情。

【讨论】:

  • 是的,我完全知道这是一个异步调用,我进入 onServiceConnected 我将绑定器的引用保留在我的自定义应用程序中,但是如果我不取消绑定,就会给我泄漏,但是如果我这样做,服务就会消失
  • 你在哪里调用 unbindService()?您的服务是否自己创建/管理线程?
  • 对于定位服务,它自行管理,在没有来自应用程序的信号时不应该做任何事情。但是我希望能够在我的应用程序进入后台时取消绑定,并在重新启动时重新绑定。对于 xmpp 服务,我在每个 Activity 上绑定/取消绑定。但有时我的行为很奇怪,包括泄漏
  • 真正的我不知道怎么做,是从一个activity中启动(绑定)一个服务,然后再使用SAME服务吗?
【解决方案2】:

这个帖子很老了,但我才发现它。

实际上,如果您的服务被绑定,只有一种方法可以继续存在:它也必须启动。文档对此不是很清楚,但是可以启动和绑定服务。

在这种情况下,服务在解除绑定时不会被销毁,它会在以下情况下被销毁:

  • 你阻止它,没有人绑定它
  • 你解除绑定,它之前已经停止了。

我制作了一个小型服务生命周期演示应用 on GitHub,它也可以在 Google Play 上使用。

希望有所帮助;)

【讨论】:

    【解决方案3】:

    如果你在一个Activity中绑定了一个服务,你也需要解绑它:

    @Override
    protected void onResume() {
    
        Log.d("activity", "onResume");
        if (locationServiceBinder == null) {
            doBindLocationService();
        }
                super.onResume();
    }
    
    @Override
    protected void onPause() {
    
        Log.d("activity", "onPause");
        if (locationServiceBinder  != null) {
            unbindService(callConnectService);
            locationServiceBinder = null;
        }
        super.onPause();
    }
    

    在哪里doBindLocationService()

    public void doBindLocationService() {
        Log.d("doBindService","called");
    
        aimConServ =  new Intent(this, LocationService.class);
        // Create a new Messenger for the communication back
        // From the Service to the Activity
        bindService(aimConServ, callConnectService, Context.BIND_AUTO_CREATE);
    }
    

    你也需要为你的XmppService做这个练习

    【讨论】:

      猜你喜欢
      • 2020-08-17
      • 2012-09-20
      • 1970-01-01
      • 1970-01-01
      • 2016-06-25
      • 2017-11-20
      • 1970-01-01
      • 1970-01-01
      • 2018-06-05
      相关资源
      最近更新 更多