TL;DR see below
A core feature of my android application is to broadcast the user's current location in a foreground service that continues to run after being unbound from the activity. I have everything working fine in terms of publishing to a channel and subscribers receiving the data from the channel. The service is working great. I'm even animating a google maps camera to follow the location received from the subscribed message.
My concern is that I'm getting this message:
I/Choreographer: Skipped 49 frames! The application may be doing too much work on its main thread.
I have of course researched this message. A lot of people seem to say it has something to do with animation, so I assume it has something to do with the map since it is the only thing animating. Though, I've also learned that the choreographer can produce this message because of other reasons.
When my application starts up, it launches a foreground service which connects to google location services using the GoogleAPIClient. After initialization, I immediately request my current location and use PubNub to broadcast the lng and lat to a channel. I then subcribe to that channel and when the message is received my MapFragmentPresenter class listens to location updates from the service. The presenter then calls the MapFragment's View (The V in MVP) to animate the camera and position the marker on each new location.
This is all working fine. I just want to make sure I'm not causing skipped frames and not putting too much work on the main thread. I'm doing very little on the main thread right now considering all the other stuff I have planned on doing on it. Right now I'm just continually repositioning the camera to follow the device's current location, pretty basic I would think.
Also, I am not using any wakelock features, yet my PubNub broadcasts are working fine. Why is this? I read somewhere that using PubNub running while the device is locked requires this, but mine is working without it.
Sorry for the long post.
Note: I do not have large resource files. I haven't even really added anything other than icons I import from AS itself.
TL;DR
I seem to be doing too much on my main thread. Can google location services and PubNub operations be done on different threads in a service and will this fix my problem?
Questions:
Should/Can I do all of the location requests on a worker thread?
Should/Can PubNub operations be on their own thread?
Is anything I'm doing bad?
My foreground service seems to be working perfectly fine while the device is asleep/locked, but I have NOT messed with WAKE_LOCK at all. Should I? What's the difference in manipulating state of lock when my service seems to be doing everything I expect?
Here's some of the code:
Thanks for taking the time!
MapViewFragment
public class MapViewFragment extends Fragment
implements OnMapReadyCallback, IMapFragment {
private static final String TAG = "MAP_VIEW_FRAGMENT";
private MapView mapView;
private GoogleMap gMap;
private IMapPresenter presenter;
private boolean mapReady;
private Handler handler;
private LatLng myLocation;
//ToDo: newInstance method
//==========================
//Fragment Lifecycle
//==========================
#Override #Nullable
public View onCreateView(LayoutInflater inflater, #Nullable ViewGroup container,
#Nullable Bundle savedInstanceState) {
mapReady = false;
presenter = new MapPresenter(this);
View v = inflater.inflate(R.layout.map_view, container, false);
handler = new Handler(Looper.getMainLooper());
mapView = (MapView) v.findViewById(R.id.mapview);
mapView.onCreate(savedInstanceState);
mapView.getMapAsync(this);
return v;
}
#Override
public void onResume() {
super.onResume();
mapView.onResume();
}
#Override
public void onDestroy() {
super.onDestroy();
mapView.onDestroy();
}
#Override
public void onLowMemory() {
super.onLowMemory();
mapView.onLowMemory();
}
public MapPresenter getPresenter(){
return (MapPresenter) presenter;
}
//==========================
//Map
//==========================
#Override
public void onMapReady(GoogleMap googleMap) {
this.gMap = googleMap;
mapReady = true;
}
#Override
public void moveToMyLocation(final LatLng locData) {
handler.post(new Runnable() {
#Override
public void run() {
gMap.addMarker(new MarkerOptions().position(locData).title("myLocation"));
gMap.moveCamera(CameraUpdateFactory.newLatLngZoom(locData,20));
Log.d(TAG,"//////////////////moveToMyLocation");
}
});
}
}
Service
public class MapService extends Service implements
GoogleApiClient.ConnectionCallbacks, GoogleApiClient.OnConnectionFailedListener,
LocationListener {
private static final String TAG = "MAP_VIEW_SERVICE";
private int REQUEST_CODE = 101;
private int NOTIFICATION_ID = 102;
private LocationRequest gLocationRequest;
private GoogleApiClient gApiClient;
private Pubnub mPubnub;
private Location lastLocation;
private String mapFragTag;
private final IBinder mBinder = new LocalBinder();
private LatLng mLatLng;
private ServiceRequestListener requestListener;
//==========================
//Service Lifecycle
//==========================
#Override
public void onCreate() {
super.onCreate();
gLocationRequest = LocationRequest.create();
gLocationRequest.setInterval(5000);
gLocationRequest.setFastestInterval(5000);
gLocationRequest.setPriority(LocationRequest.PRIORITY_HIGH_ACCURACY);
gApiClient = new GoogleApiClient.Builder(this)
.addApi(LocationServices.API)
.addConnectionCallbacks(this)
.addOnConnectionFailedListener(this)
.build();
mPubnub = new Pubnub(
getString(R.string.pubnub_publish_key)
,getString(R.string.pubnub_subscribe_key));
try{
mPubnub.subscribe("Channel-d2160eqlk",subscribeCallback);
}catch (PubnubException e) {
Log.e("**MapService**", e.toString());
}
gApiClient.connect();
setupAndLaunchForeground();
}
#Override
public int onStartCommand(Intent intent, int flags, int startId) {
return START_STICKY;
}
#Nullable #Override
public IBinder onBind(Intent intent) {
return mBinder;
}
#Override
public void onDestroy() {
super.onDestroy();
if(gApiClient.isConnected()) {
gApiClient.disconnect();
}
}
public void setRequestListener(ServiceRequestListener requestListener) {
this.requestListener = requestListener;
}
//==========================
//StartForeground
//==========================
private void setupAndLaunchForeground() {
NotificationCompat.Builder builder = new NotificationCompat.Builder(this);
builder.setSmallIcon(R.mipmap.ic_launcher)
.setContentTitle("Service Running")
.setTicker("AppName Services Initiated")
.setWhen(System.currentTimeMillis())
.setOngoing(true);
Intent startIntent = new Intent(this, MapViewFragment.class);
PendingIntent contentIntent = PendingIntent.getActivity(this,
REQUEST_CODE, startIntent, 0);
builder.setContentIntent(contentIntent);
Notification notification = builder.build();
NotificationManager notificationManager =
(NotificationManager) getSystemService(Context.NOTIFICATION_SERVICE);
notificationManager.notify(NOTIFICATION_ID, notification);
startForeground(NOTIFICATION_ID,notification);
}
//==========================
//Google API Client
//==========================
#Override
public void onConnected(#Nullable Bundle bundle) {
PackageManager manager = getPackageManager();
if(manager.checkPermission(Manifest.permission.ACCESS_FINE_LOCATION,"com.firsttread.appname")
== PackageManager.PERMISSION_GRANTED){
LocationServices.FusedLocationApi.requestLocationUpdates(gApiClient, gLocationRequest, this);
lastLocation = LocationServices.FusedLocationApi.getLastLocation(gApiClient);
}
}
#Override
public void onConnectionSuspended(int i) {
}
#Override
public void onConnectionFailed(#NonNull ConnectionResult connectionResult) {
}
//==========================
//Location
//==========================
#Override
public void onLocationChanged(Location location) {
broadcastLocation(location);
this.lastLocation = location;
Log.d("****LocationChange****","Lat: " + location.getLatitude() + "Lng: " + location.getLongitude());
}
//==========================
//PubNub
//==========================
private void broadcastLocation(Location location){
JSONObject message = new JSONObject();
try{
message.put("lat", location.getLatitude());
message.put("lng", location.getLongitude());
}catch (JSONException e){
Log.e("MapService", e.toString());
}
mPubnub.publish("ChannelName", message, publishCallback);
}
Callback publishCallback = new Callback() {
#Override
public void successCallback(String channel, Object response) {
Log.d("**PUBNUB**", response.toString());
}
#Override
public void errorCallback(String channel, PubnubError error) {
Log.e("**PUBNUB**", error.toString());
}
};
Callback subscribeCallback = new Callback() {
#Override
public void successCallback(String channel, Object message) {
JSONObject jsonMessage = (JSONObject) message;
try {
double mLat = jsonMessage.getDouble("lat");
double mLng = jsonMessage.getDouble("lng");
if(requestListener != null){
sendLocation(new LatLng(mLat,mLng));
}
} catch (JSONException e) {
Log.e("**PUBNUB_ERROR**", e.toString());
}
}
};
//==========================
//Location Data Methods
//==========================
private void sendLocation(LatLng locData){
requestListener.retrieveLocation(locData);
}
//==========================
//MapInterface
//==========================
public interface ServiceRequestListener {
void retrieveAppNameLocations(HashMap<String,Long> memberLocations);
void retrieveLocation(LatLng locData);
}
//==========================
//ServiceBinder
//==========================
public class LocalBinder extends Binder {
public MapService getService() {
return MapService.this;
}
}
}
Some answers to your questions:
1. Should/Can I do all of the location requests on a worker thread?
You shouldn't need to do anything special other than just subscribe to the channel that will have the location data published to it.
2. Should/Can PubNub operations be on their own thread?
They will be, just use the async APIs, not the sync APIs (you can't use sync in Android anyways without extra work, otherwise Android will throw exception).
3. Is anything I'm doing bad? My foreground service seems to be working perfectly fine while the device is asleep/locked, but I have NOT messed with WAKE_LOCK at all. Should I?
At the time you asked this question, you might have been able config the WAKE_LOCK but might not be permitted anymore in lates Android OS (without additional permissions from end user, perhaps) but shouldn't matter. Just use push notifications when app is in background.
4. What's the difference in manipulating state of lock when my service seems to be doing everything I expect?
Not really sure what you mean here so would need more details.
If you are still having issues with the above, please submit full details to PubNub Support. Send sample project zipped (if possible), your PubNub sub-key and PubNub SDK logs that captures any scenarios you are having issues with.
Related
I followed the basic android documentation to implement a Service, triggered repeatedly by AlarmManager every 40 seconds. Inside the service I register GPS listener, and if I don't get fix within 30 seconds I call stopSelf(), this in order to avoid 2 "concurrent" services running together. However if I do have fix within less then 30 seconds, I perform some logic and after I done I call stopSelf() - Assuming it all will take less then 40 seconds so again I have no issues of "concurrent" services running...
When I log print the order of execution of various Service methods it doesn't make any sense:
onCreate is called only once, while onStartCommand is triggered every 40 seconds.
The GPS is never fixed, maybe the fact that the hosting Activity also registered and do have GPS fix interfere here? (I testing outdoors and the activity does get fix)
This is my implementation - Pretty much straightforward googles android documentation:
public class DirectionService extends Service implements Constants {
private LocationManager mLocationManager;
private LocationListener mLocationListeners;
private Context mContext;
private Looper mServiceLooper;
private ServiceHandler mServiceHandler;
#Override
public IBinder onBind(Intent arg0) {
return null; //not binding
}
#Override
public void onCreate() {
HandlerThread thread = new HandlerThread("ServiceStartArguments", Process.THREAD_PRIORITY_BACKGROUND);
thread.start();
mServiceLooper = thread.getLooper();
mServiceHandler = new ServiceHandler(mServiceLooper);
mContext = getApplicationContext();
}
#Override
public int onStartCommand(Intent intent, int flags, int startId) {
//For each start request, send a message to start a job and deliver the start ID so we know which request we're stopping when we finish the job
Message msg = mServiceHandler.obtainMessage();
msg.arg1 = startId;
mServiceHandler.sendMessage(msg);
return START_STICKY;
}
//Handler that receives messages from the thread
private final class ServiceHandler extends Handler {
public ServiceHandler(Looper looper) {
super(looper);
}
/**
* The real work done after we have (first) fixed location and from there we stop the service.
* Therefore we pass the start id.
*/
#Override
public void handleMessage(final Message msg) {
if (mLocationManager == null) {
mLocationManager = (LocationManager) getApplicationContext().getSystemService(Context.LOCATION_SERVICE);
mLocationListeners = new LocationListener(msg.arg1);
}
try {
mLocationManager.requestLocationUpdates(LocationManager.GPS_PROVIDER, GPS_UPDATE_TIME, 0, mLocationListeners);
mLocationManager.addGpsStatusListener(mGPSStatusListener);
} catch (Exception e) {
stopSelf(msg.arg1);
}
//Start timer for GPS to get fix location. Else we might have new concurrent instance of service
new CountDownTimer(30000, 15000) {
public void onTick(long millisUntilFinished) {}
public void onFinish() {
stopSelf(msg.arg1);
}
}.start();
}
}
GpsStatus.Listener mGPSStatusListener = new GpsStatus.Listener() {
public void onGpsStatusChanged(int event) {
switch (event)
{
case GpsStatus.GPS_EVENT_FIRST_FIX:
if (ContextCompat.checkSelfPermission(mContext, Manifest.permission.ACCESS_FINE_LOCATION) == PackageManager.PERMISSION_GRANTED
|| ContextCompat.checkSelfPermission(mContext, Manifest.permission.ACCESS_COARSE_LOCATION) == PackageManager.PERMISSION_GRANTED) {
if (mLocationManager.getLastKnownLocation(LocationManager.GPS_PROVIDER) != null) {
isGpsFixed = true;
}
}
break;
default:
break;
}
}
};
private class LocationListener implements android.location.LocationListener {
private int startId;
public LocationListener(int startId) {
this.startId = startId;
}
#Override
public void onLocationChanged(Location location) {
if (isGpsFixed == true && location.getLongitude() != 0.0 && location.getLatitude() != 0.0 && isAlreadySentToCheck == false) {
isAlreadySentToCheck = true;
startLogic(startId);
}
}
#Override
public void onProviderDisabled(String provider) {}
#Override
public void onProviderEnabled(String provider) {}
#Override
public void onStatusChanged(String provider, int status, Bundle extras) {}
}
private void startLogic(final int startId) {
//...
stopSelf(startId);
}
#Override
public void onDestroy() {
super.onDestroy();
if (mLocationManager != null) {
try {
mLocationManager.removeUpdates(mLocationListeners);
} catch (Exception ex) {}
}
}
your service running many time because of start_sticky
if your service is killed by Android due to low memory, and Android clears some memory, then...
STICKY: ...Android will restart your service, because that particular flag is set.
NOT_STICKY: ...Android will not care about starting again, because the flag tells Android it shouldn't bother.
REDELIVER_INTENT: ...Android will restart the service AND redeliver the same intent to onStartCommand() of the service, because, again, of the flag.
suggest to your start_not_sticky
I have set up an environment where the app receives location updates, which is handle on the onLocationChanged callback.
// Setup the client.
mGoogleApiClient = new GoogleApiClient.Builder(this)
.addConnectionCallbacks(this)
.addOnConnectionFailedListener(this)
.addApi(LocationServices.API)
.build();
}
// Register the location update.
LocationServices.FusedLocationApi.requestLocationUpdates(mGoogleApiClient, mLocationRequest, this);
// Interface callback. Called every 5 seconds.
#Override
public void onLocationChanged(Location location) {
// Save the location coordinates to a file.
}
So far so good. Then, for my purposes, I saw the need of triggering the onLocationChanged callback even if the app is not running - that's where BroadcastReceivers and Services come in.
I want a BroadcastReceiver to start a Service, that would save the location coordinates updates do a file. So, in my mind, the architecture would go something like:
// Register the BroadcasReceiver to the activity.
registerReceiver(mBroadcastReceiver, new IntentFilter());
// The BroadcastReceiver
public static class MyBroadcastReceiver extends BroadcastReceiver{
#Override
public void onReceive(Context context, Intent intent) {
MyActivity.myContext.startService(new Intent(context, MyService.class));
}
}
// The Service class.
public static class MyService extends Service {
private boolean isRunning = false;
#Override
public void onCreate() {
isRunning = true;
}
#Override
public int onStartCommand(Intent intent, int flags, int startId) {
//Creating new thread for my service.
//Always write your long running tasks in a separate thread, to avoid ANR
new Thread(new Runnable() {
#Override
public void run() {
// Save location updates.
}
//Stop service once it finishes its task
stopSelf();
}
}).start();
return Service.START_STICKY;
}
#Override
public IBinder onBind(Intent arg0) {
return null;
}
#Override
public void onDestroy() {
isRunning = false;
}
}
All LocationServices API setup process (the first block of code below) is inside the activity onCreate method.
So, how can I receive location updates from the tread's run() method created by the Service, if the app is not running? The whole design is to be like that:
App not running/destroyed > A specific action trigger the Broadcasreceiver > The BroadcastReceiver trigger the Service > The Service trigger the location updates and save it to a file.
GooglePlayServices recently changed from the way you detect the users activity - from using ActivityRecognitionClient to ActivityRecognitionApi. I have followed all the examples I can find but must have missed something.
After making the call to GoogleApiClient.Builder(mContext).addApi(ActivityRecognition.API)...build() I was expecting that one of the connection callback methods would be called. I have logging and breakpoints in all the callback methods but none of them are ever called.
OnReceive() and CallClient() are called as expected and the manifest file includes: uses-permission android:name="com.google.android.gms.permission.ACTIVITY_RECOGNITION"
What am I missing? I would love to get to the bottom of this given the amount of time I have wasted so far.
(P.S. It's my own Logging library - it is not part of the issue)
public class BootAtStartupReceiver extends BroadcastReceiver implements GooglePlayServicesClient.ConnectionCallbacks, GooglePlayServicesClient.OnConnectionFailedListener, GoogleApiClient.ConnectionCallbacks,
GoogleApiClient.OnConnectionFailedListener{
private final String TAG = getClass().getName();
private PendingIntent mpIntent;
private static GoogleApiClient mGoogleApiClient;
private Context mContext;
#Override
public void onReceive(Context context, Intent intent) {
Logging.log(Logging.enumLoggingLevel.d,TAG,"inside onReceive: " + intent.getAction());
if ((intent.getAction().equals(Intent.ACTION_BOOT_COMPLETED)) || (intent.getAction().equals(BroadcastIntentConstants.ACTIVITY_FIRST_TIME_CALL_SERVICE)))
{
mContext = context;
callClient();
}
}
private void callClient() {
Logging.log(Logging.enumLoggingLevel.d,TAG,"inside callClient");
int resp = GooglePlayServicesUtil.isGooglePlayServicesAvailable(mContext);
if (resp == ConnectionResult.SUCCESS) {
mGoogleApiClient = new GoogleApiClient.Builder(mContext)
.addApi(ActivityRecognition.API)
.addConnectionCallbacks(this)
.addOnConnectionFailedListener(this)
.build();
} else {
Logging.log(Logging.enumLoggingLevel.e, getClass().getName(), "Google play Services are not available.");
}
}
#Override
public void onConnected(Bundle bundle) {
Logging.log(Logging.enumLoggingLevel.d,TAG,"inside onConnected");
Intent intent = new Intent(mContext, ActivityRecognitionIntentService.class);
mpIntent = PendingIntent.getService(mContext, 0, intent, PendingIntent.FLAG_UPDATE_CURRENT);
ActivityRecognition.ActivityRecognitionApi.requestActivityUpdates(mGoogleApiClient, 1000, mpIntent);
}
#Override
public void onDisconnected() {
Logging.log(Logging.enumLoggingLevel.d,TAG,"inside onDisconnected");
}
#Override
public void onConnectionSuspended(int i) {
Logging.log(Logging.enumLoggingLevel.d,TAG,"inside onConnectionSuspended");
}
#Override
public void onConnectionFailed(ConnectionResult connectionResult) {
Logging.log(Logging.enumLoggingLevel.d,TAG,"inside onConnectionFailed");
}
}
Are you missing the call to connect() after the build? The callbacks dont fire unless you call connect.
mGoogleApiClient.connect()
I am trying to make a location tracking application on an android phone, it will be just same as the built-in google map in the phone. It will continue to track the phone even the app is close, so it will be running in the background of other applications.
I am thinking of splitting up both the classes, User Interface (Google Map) and location tracking, where the location tracking will always run but the google map will only display when the user open the application. Thus this is what I reached so far.
MapDisplay class for Google Map
public class MapDisplay extends Activity {
private GoogleMap map;
private LocationService locationService;
private Intent locationServiceIntent;
private Location myLocation;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_map_display);
map = ((MapFragment) getFragmentManager().findFragmentById(R.id.googleMap)).getMap();
map.setMapType(GoogleMap.MAP_TYPE_NORMAL);
map.setMyLocationEnabled(true);
locationServiceIntent = new Intent(this, LocationService.class);
x=0;
}
#Override
protected void onPause() {
super.onPause();
}
#Override
protected void onResume() {
super.onResume();
startService(locationServiceIntent);
bindService(locationServiceIntent, locationServiceConnection, Context.BIND_AUTO_CREATE);
}
#Override
public void updateLocation()
{
// for testing purpose, to make sure it will update periodically
Toast.makeText(MapDisplay.this, String.valueOf(myLocation.getLatitude()), Toast.LENGTH_SHORT).show();
}
private ServiceConnection locationServiceConnection = new ServiceConnection() {
#Override
public void onServiceConnected(ComponentName name, IBinder service) {
locationService = ((LocationService.LocationBinder)service).getService();
myLocation = locationService.getMyLocation();
updateLocation();
}
#Override
public void onServiceDisconnected(ComponentName name) {
locationService = null;
}
};
}
LocationService class
public class LocationService extends Service implements LocationListener
{
private LocationManager locationManager;
private Location myLocation;
private IBinder locationBinder = new LocationBinder();
public class LocationBinder extends Binder
{
public LocationService getService()
{
return LocationService.this;
}
}
#Override
public IBinder onBind(Intent intent) {
return locationBinder;
}
#Override
public int onStartCommand(Intent intent, int flags, int startId)
{
locationManager = (LocationManager)getSystemService(Context.LOCATION_SERVICE);
myLocation = null;
boolean networkProviderAvailable = locationManager.isProviderEnabled(LocationManager.NETWORK_PROVIDER);
boolean gpsProviderAvailable = locationManager.isProviderEnabled(LocationManager.GPS_PROVIDER);
if(networkProviderAvailable)
{
locationManager.requestLocationUpdates(LocationManager.NETWORK_PROVIDER, 0, 0, this);
}
else if(gpsProviderAvailable)
{
locationManager.requestLocationUpdates(LocationManager.GPS_PROVIDER, 0, 0, this);
}
else
{
stopSelf();
}
return super.onStartCommand(intent, flags, startId);
}
public Location getMyLocation()
{
return myLocation;
}
#Override
public void onLocationChanged(Location location) {
myLocation = location;
}
#Override
public void onProviderDisabled(String arg0) {
}
#Override
public void onProviderEnabled(String arg0) {
}
#Override
public void onStatusChanged(String arg0, int arg1, Bundle arg2) {
}
}
Using code above I experienced application crash because of this line
myLocation = locationService.getMyLocation();
String.valueOf(myLocation.getLatitude())
It can't get the location from LocationService class.
So, my questions are:
1) is this a good way to make the application?
2) how to periodically call the updateLocation() in MapDisplay when there are new updates in onLocationChanged method?
I will be much appreciate if someone can help me on this.
You have to account for the case that you have not yet received a location. To do that, your client code needs to check the return of getLocation for null, and handle accordingly.
Additionally you may want some more intelligence in onLocationChanged. Right now if a gps location comes in and then a network location comes in, the network location will overwrite the gps location, despite being less accurate. I'd take a look at some code I wrote at http://gabesechansoftware.com/location-tracking/ You'll see a class FallbackLocationTracker which will track both gps and network location, returning the most accurate location received so far. I think it does what you're trying to do.
I want to make the following:
1]- listen to the change of the GPS location of the phone and send it to server to track user location continuously
2]- I have found an example to find the GPS location using LocationListener
3]- I have found a way to open my application when device restart
I need some help to be able to send this data even if user put the application in background
Any help here?
this service should work in the background
The LocationClient is the main entry point for location related APIs, such as location and geofence.
Use the LocationClient to:
Connect and disconnect to Google Location Services.
Request/remove location update callbacks.
Request/remove geofences.
In order to establish a connection, call connect() and wait for the onConnected(android.os.Bundle) callback.
LocationRequest objects are used to request a quality of service for location updates from the LocationClient.
in LocationRequest, you can set parameters there such as the accuracy of the location and time interval between location updates.
onLocationChanged will get called according to time interval you set in LocationRequest and from there you can update your server.
the service does not run in the background so you will need to update the server with AsyncTask or some other way, just make sure the server updates are done on a background thread.
public class LocationUpdatesService extends Service implements GooglePlayServicesClient.ConnectionCallbacks,
GooglePlayServicesClient.OnConnectionFailedListener,
LocationListener {
private static int LOCATION_UPDATE_INTERVAL = 30000; // how often you will get a location update (this is in milliseconds)
private LocationClient locationClient;
private LocationRequest locationRequest;
private boolean isConnected = false;
#Override
// onCreate is called when the service gets started (from an Activity) than immediately calls onStartCommand
public void onCreate() {
super.onCreate();
if (servicesConnected()) {
startLocationUpdates();
} else {
// isGooglePlayServicesAvailable FAILURE
}
}
#Override
public int onStartCommand(Intent intent, int flags, int startId) {
return Service.START_STICKY;
}
#Override
public IBinder onBind(Intent intent) {
return null;
}
private boolean servicesConnected() {
int resultCode = GooglePlayServicesUtil.isGooglePlayServicesAvailable(this);
if (ConnectionResult.SUCCESS == resultCode) {
return true;
} else {
return false;
}
}
public void startLocationUpdates() {
locationRequest = LocationRequest.create();
locationRequest.setInterval(LOCATION_UPDATE_INTERVAL);
locationRequest.setPriority(LocationRequest.PRIORITY_HIGH_ACCURACY);
locationRequest.setFastestInterval(LOCATION_UPDATE_INTERVAL);
locationClient = new LocationClient(this, this, this);
locationClient.connect();
isConnected = true;
}
#Override
public void onDestroy() {
if (locationClient.isConnected()) {
onDisconnectClient();
} else {
// locationClient is disconnected
}
super.onDestroy();
}
private void onDisconnectClient() {
isConnected = false;
locationClient.removeLocationUpdates(this);
locationClient.disconnect();
locationRequest = null;
locationClient = null;
}
#Override
public void onLocationChanged(Location location) {
// update server from here with AsyncTask (or some other way but in the background)
}
#Override
public void onConnectionFailed(ConnectionResult connectionResult) {
}
#Override
public void onConnected(Bundle bundle) {
locationClient.requestLocationUpdates(locationRequest, this);
}
#Override
public void onDisconnected() {
}
}
helpful links:
http://developer.android.com/reference/android/app/Service.html
http://developer.android.com/guide/components/services.html
http://developer.android.com/reference/android/location/LocationListener.html
https://developer.android.com/reference/com/google/android/gms/location/LocationRequest.html
https://developer.android.com/reference/com/google/android/gms/location/LocationListener.html