Android 安卓服务:活动服务沟通的良好实践

Android 安卓服务:活动服务沟通的良好实践,android,android-activity,service,Android,Android Activity,Service,在我的Android应用程序中,我在“服务”类中使用“LocationService”。一些教程推荐这种做法,以便 跨活动的永久位置检查。然而,尽管有一些很好的文档,我仍然有一个关于 活动与我的服务之间的通信 这是我的位置服务类: public class LocationService extends Service { public static LocationManager locationManager; public static LocationListene

在我的Android应用程序中,我在“服务”类中使用“LocationService”。一些教程推荐这种做法,以便 跨活动的永久位置检查。然而,尽管有一些很好的文档,我仍然有一个关于 活动与我的服务之间的通信

这是我的位置服务类:

public class LocationService extends Service {

    public static  LocationManager locationManager;
    public static  LocationListener listener;
    private static Location currentLocation = null;

    @Override
    public void onCreate() {
        super.onCreate();
    }

     @Override
     public void onStart(Intent intent, int startId) {

        locationManager = (LocationManager) getSystemService(Context.LOCATION_SERVICE);
        listener = new LocationListener() {

           @Override
           public void onLocationChanged(Location location) {
               currentLocation = location;
               System.out.println("Current Location: " + currentLocation);
           }

           @Override
           public void onStatusChanged(String s, int i, Bundle bundle) {
           }

           @Override
           public void onProviderEnabled(String s) {
           }

           @Override
           public void onProviderDisabled(String s) {
           }
       };
   }

    @Override
    public IBinder onBind(Intent intent) {
        return null;
    }

    @Override
    public void onDestroy() {
        locationManager.removeUpdates(listener);
    }

    public static Location getCurrentLocation() {
        return currentLocation;
    }
这是我的全球课程的一部分:

...
@Override
public void onCreate() {
    super.onCreate();

    if(!LocationService.isRunning()) {
        Intent intent = new Intent(this, LocationService.class);
        startService(intent);
    }
}
...
这是我的活动课:

public class ScreenActivity extends FragmentActivity {

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.screen);
    }

    if (usesPosition) {
        Location tLoc = LocationService.getCurrentLocation();
        TextView t = (TextView) findViewById(R.id.tv);
        t.setText(tLoc.toString());
    }
}
private ServiceConnection locationServiceConnection = new ServiceConnection() {
    @Override
    public void onServiceDisconnected(ComponentName name) {
        locationServiceBound = false;
        System.out.println("Service disconnected");
    }

    @Override
    public void onServiceConnected(ComponentName name, IBinder service) {
        com.ma.sainz.geoobserver.Tools.Services.LocationService.MyBinder myBinder = (com.ma.sainz.geoobserver.Tools.Services.LocationService.MyBinder) service;
        locationService = myBinder.getService();
        locationServiceBound = true;
        System.out.println("Service bound");
    }
};
我觉得这不是一种优雅的方式,甚至可能是错误的。我确实有一个很好的位置,但我觉得我无法访问该服务,但是 而是将其视为一个静态类。我还不熟悉将服务绑定到活动的概念,所以我想知道我是否真的需要 这样做

编辑1

谢谢你的第一个答案!这已经帮了我一点忙了。这是我的活动课的一部分:

public class ScreenActivity extends FragmentActivity {

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.screen);
    }

    if (usesPosition) {
        Location tLoc = LocationService.getCurrentLocation();
        TextView t = (TextView) findViewById(R.id.tv);
        t.setText(tLoc.toString());
    }
}
private ServiceConnection locationServiceConnection = new ServiceConnection() {
    @Override
    public void onServiceDisconnected(ComponentName name) {
        locationServiceBound = false;
        System.out.println("Service disconnected");
    }

    @Override
    public void onServiceConnected(ComponentName name, IBinder service) {
        com.ma.sainz.geoobserver.Tools.Services.LocationService.MyBinder myBinder = (com.ma.sainz.geoobserver.Tools.Services.LocationService.MyBinder) service;
        locationService = myBinder.getService();
        locationServiceBound = true;
        System.out.println("Service bound");
    }
};
其中,
myBinder
是在
LocationService
中定义的类。 这就是我的新onStart()-活动方法:

@Override
protected void onStart() {
    super.onStart();

    Intent locationServiceIntent = new Intent(this, com.ma.sainz.geoobserver.Tools.Services.LocationService.class);
    bindService(locationServiceIntent, locationServiceConnection, Context.BIND_AUTO_CREATE);
    locationService.requestBackgroundLocation();
    System.out.println("onStart");
}
startService(locationServiceIntent)
在以前的活动中完成

但是,locationService暂时为空。所以服务连接需要一些时间。我如何知道服务何时连接


假设我想实现一个
LocalBroadcast
,这会是对服务实现的补充吗?你有关于如何开始的提示吗?因为如果我在位置更新到达后立即发送位置更新,我就不用等待服务连接了。

是的,不要这样做-这不是很好,但也会导致内存泄漏。 Android服务可以通过其他组件绑定到ABE,请参阅:。 您的活动或其他服务将绑定到您的位置服务,并使用此服务提供的接口。请注意,至少保留一个连接时,服务将运行。启动并绑定到服务,然后它将运行,直到您停止它,并且您将能够通过绑定器使用来自该服务的显式接口。
另一个很好的技术是使用EventBus(greenRobot)在活动和服务之间传递粘性事件。事件将等待另一个组件初始化并接收该事件。您可以通过onPause和onResume方法订阅该活动并取消订阅。

您的设计确实不是很好。想一想:通常你不只是想得到一个位置,而是想保持它的更新。这意味着当发生此类更新时,应通知您的活动

您在这里几乎没有选择:

  • 绑定服务并对其执行常规方法调用(获取位置、注册/取消注册侦听器)
  • 使用
    LocalBroadcastManager
    将位置更新从服务广播到活动
  • 使用一些事件总线(我最喜欢的-GreenRobot的事件总线)将位置更新从服务广播到活动

  • 我个人使用后一种方法:服务在位置更新时向事件总线发布“粘性”事件,活动在
    onResume()
    中查询这些事件并订阅更新。这样,您的
    服务就不需要一直运行了-在需要位置时启动它,以所需的精度获取位置,然后停止服务以避免消耗电池。

    谢谢,这是一个开始。我绑定了服务,但是现在我的服务在连接之前是空的。我编辑了我的问题,并感谢您提供更多提示:)我不想在这里回答关于绑定服务的问题,因为关于SO的问题应该是关于单个主题的。通常,在调用
    onServiceConnected()
    callback之前,不应使用该服务。在您的情况下,可以将
    locationService.requestBackgroundLocation()放在onServiceConnected()
    中执行code>并查看发生了什么。哦,好的。我没有看到onServiceConnected()函数的依赖性。是的,那听起来不错。那我下次再看广播。现在它正按照我想要的方式工作。谢谢