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
Related
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.
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.
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.
So, I was asked to make a Location Tracker.
Location tracker should track even if the app is tuned off...
My idea is to start my own service (lets call it TrackingService) from the activity by calling startService(intent); so the service will run forever (I guess..) and then connect to Location Service from my own created TrackingService. TrackingService should listen to location changes after app was turned off.
I write some code, started TrackingService, and requested location updates in a new thread.
Anyway, location updates stops after I quit app but service is still running.
EDIT:
Ok, so i manage to improve my code a bit, so now when my app is running, i get Log's that my thread (that runs in separate service) is running and that it receives Location Updates.
When i quit y app I still get Log that my thread is running but it does not receives Location Updates...
Anyone can point my a reason why?
P.S. I know that probably there are better ways to get the job done, but I really hoping to fix my code.
Here goes service class
public class TrackingService extends Service {
// DEBUG
public final static String TAG = "TrackingService";
public final static boolean D = true;
// Global constants
private static final long UPDATE_INTERVAL = 10000; // Update frequency in milliseconds
private static final long FASTEST_INTERVAL = 4000; // A fast frequency ceiling in milliseconds
//
int mStartMode; // indicates how to behave if the service is killed
private final IBinder mBinder = new LocalBinder(); // interface for clients that bind
boolean mAllowRebind; // indicates whether onRebind should be used
private int number; // testavimui
LocationThread mLocationThread;
#Override
public void onCreate() {
if (D) {Log.d(TAG, "service - onCreated started");};
mLocationThread = new LocationThread(this);
mLocationThread.start();
// mLocationThread.run();
}
#Override
public int onStartCommand(Intent intent, int flags, int startId) {
if (D) {Log.d(TAG, "service - onStartCommand started");};
// The service is starting, due to a call to startService()
return mStartMode;
}
#Override
public IBinder onBind(Intent intent) {
if (D) {Log.d(TAG, "service - onBind started");};
// A client is binding to the service with bindService()
return mBinder;
}
#Override
public boolean onUnbind(Intent intent) {
if (D) {Log.d(TAG, "service - onUnBind started");};
// All clients have unbound with unbindService()
return mAllowRebind;
}
#Override
public void onRebind(Intent intent) {
if (D) {Log.d(TAG, "service - onReBind started");};
// A client is binding to the service with bindService(),
// after onUnbind() has already been called
}
#Override
public void onDestroy() {
if (D) {Log.d(TAG, "service - onDestroy started");};
// The service is no longer used and is being destroyed
mLocationThread.cancel();
}
public class LocalBinder extends Binder {
TrackingService getService() {
// Return this instance of LocalService so clients can call public methods
return TrackingService.this;
}
}
public int number(){
number += 1;
return number;
}
private class LocationThread extends Thread implements
GooglePlayServicesClient.ConnectionCallbacks,
GooglePlayServicesClient.OnConnectionFailedListener,
LocationListener{
private boolean keepOn;
private Context mContext;
private LocationClient mLocationClient;
private LocationRequest mLocationRequest;
public LocationThread (Context context){
mContext = context;
keepOn = true;
}
public void cancel() {
keepOn = false;
if (D){Log.d(TAG, "thread was canceled");};
}
public void run(){
mLocationRequest = LocationRequest.create();
mLocationRequest.setPriority(LocationRequest.PRIORITY_HIGH_ACCURACY); // Use high accuracy
mLocationRequest.setInterval(UPDATE_INTERVAL); // Set the update interval to 5 seconds
mLocationRequest.setFastestInterval(FASTEST_INTERVAL); // Set the fastest update interval to 1 second
mLocationClient = new LocationClient(mContext, this, this);
mLocationClient.connect();
while (keepOn){
try {
Thread.sleep(10000);
if(D){Log.d(TAG, "thread running");};
} catch (Exception e){
}
}
}
#Override
public void onConnectionFailed(ConnectionResult result) {
if(D){Log.d(TAG, "connection failed");};
}
#Override
public void onConnected(Bundle connectionHint) {
if(D){Log.d(TAG, "connected to location service");};
mLocationClient.requestLocationUpdates(mLocationRequest, this);
}
#Override
public void onDisconnected() {
if(D){Log.d(TAG, "disconnected from location service");};
}
#Override
public void onLocationChanged(Location location) {
if(D){Log.d(TAG, "Location changed");};
}
}
}
Although the documentation is not specific about it, I suggest you perform the call to LocationManager.requestLocationUpdates() in the main (UI) thread. You can use a Handler to accomplish that if the call originates from a separate thread.
BTW, if you want your service to run in a separate thread, I suggest you extend IntentService and override the onHandleIntent() method, it is easier that way.
Further advice:
If you want your Service to run even when the phone is in sleep mode, you need a wake lock.
Hint: You don't have to make it run continuosly, that will consume a lot of battery needlessly. Make your Servicecollect a single location, save it to a local database or deliver it to a bound activity and then stop, and then schedule that Service to run from time to time using AlarmManager.
It goes like this: AlarmManager calls a WakefulBroadcastReceiver, which by its turn calls your Service.
I suggest you read the WakefulBroadcastReceiver documentation, it will provide a wake lock for your service automatically (which you have to manually release before the service stops).