Reputation: 123
In my Android application, I'm using a 'LocationService' within a 'Service' class. Several tutorials recommend this practice in order to have a permanent location check across activities. However, despite some good documentation out there, I still have a question concerning the communication between an activity and my service.
This is my LocationService class:
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;
}
This is part of my Global class:
...
@Override
public void onCreate() {
super.onCreate();
if(!LocationService.isRunning()) {
Intent intent = new Intent(this, LocationService.class);
startService(intent);
}
}
...
And this is my Activity class:
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());
}
}
I feel like this is not an elegant way, possible even wrong. I do get a good location, but I feel like I don't access the service, but rather treat it like a static class. I'm not yet familiar with the concept of binding services to activities, so I wonder if I really do need to do that.
EDIT 1
Thanks for the first answers! That helped me out a bit already. This is now part of my Activity class:
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");
}
};
where myBinder
is a class defined in the LocationService
.
And that is my new onStart()-Method of my Activity:
@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)
is done in a previous activity.
However, locationService is null for a while. So Service connection takes some time. How do I know when the Service is connected?
And assuming that I'd like to implement a LocalBroadcast
, would that be in addition to the service implementation? Do you have a hint on how to start on that? Because if I'll send locationUpdates as soon as they're there, I wouldn't bother with waiting for the service to connect.
Upvotes: 1
Views: 503
Reputation: 16268
What you have is really not a very good design. Think about this: usually you would like not just get a location, but keep it updated. This means that your Activity should be notified when such updates occur.
You got few options here:
LocalBroadcastManager
in order to broadcast location updates from the Service to ActivitiesI personally use the latter approach: the Service posts "sticky" events to Event Bus upon location update, and Activities query these events in onResume()
and also subscribe for updates. This way your Service
won't need to be always running - start it when you need the location, get the location with desired accuracy, and stop the service in order to not consume battery.
Upvotes: 1
Reputation: 3282
Yes, do not do that - it is not not ellegant, but will also cause memory leak. Android Service can be bound to aby other component, see: https://developer.android.com/guide/components/bound-services.html . Your actvity or another service will bind to your location service and use interface thise ServiceProvides. Notice, service will be running when at least one connection remain. Start and bind to service and then it will run until you stop it and you will be able to use explicit interface from that service by Binder. Another good technic - using EventBus (greenRobot) for passing sticky events between Activity and Service. Event will wait until another component is initialized and receve that event. You can subscribe to that event and unsubscribe from it in onPause and onResume method.
Upvotes: 0