I am writing a location service App that log where the user has been every minute.
Should I create a service for the GPS process? OR just create the LocationManager at the Activity? Which one is better?
Moreover, I have tried to hide the application by pressing hardware home button and turn off GPS at Setting -> Location. I found that the App closed automatically within an hour.
Is it possible to keep the application always alive?
I highly recommend creating the gps at the very least as a thread in the activity, if you want to be slick set it up as a service and broadcast intents from inside an asynctask. Setting it up as a service makes it a bit modular if you want to use it for other applications or in other activities. Thats the way I implemented it.
Its also easier to control the lifetime of your gps readings if you run it from a service instead of your activity, so service doesnt get interrupted if you do switch activities etc.. example of asynctask portion below:
/** Begin async task section ----------------------------------------------------------------------------------------------------*/
private class PollTask extends AsyncTask<Void, Void, Void> { //AsyncTask that listens for locationupdates then broadcasts via "LOCATION_UPDATE"
// Classwide variables
private boolean trueVal = true;
Location locationVal;
//Setup locationListener
LocationListener locationListener = new LocationListener(){ //overridden abstract class LocationListener
#Override
public void onLocationChanged(Location location) {
handleLocationUpdate(location);
}
#Override
public void onProviderDisabled(String provider) {
}
#Override
public void onProviderEnabled(String provider) {
}
#Override
public void onStatusChanged(String provider, int status,
Bundle extras) {
}
};
/** Overriden methods */
#Override
protected Void doInBackground(Void... params) {
//This is where the magic happens, load your stuff into here
while(!isCancelled()){ // trueVal Thread will run until you tell it to stop by changing trueVal to 0 by calling method cancelVal(); Will also remove locationListeners from locationManager
Log.i("service","made it to do in background");
try {
Thread.sleep(100);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
return null;
}
#Override
protected void onCancelled(){
super.onCancelled();
stopSelf();
}
#Override
protected void onPreExecute(){ // Performed prior to execution, setup location manager
locationManager = (LocationManager)getSystemService(Context.LOCATION_SERVICE);
if(gpsProvider==true){
locationManager.requestLocationUpdates(LocationManager.GPS_PROVIDER, 0, 0, locationListener);
}
if(networkProvider==true){
locationManager.requestLocationUpdates(LocationManager.NETWORK_PROVIDER, 0, 0, locationListener);
}
}
#Override
protected void onPostExecute(Void result) { //Performed after execution, stopSelf() kills the thread
stopSelf();
}
#Override
protected void onProgressUpdate(Void... v){ //called when publishProgress() is invoked within asynctask
//On main ui thread, perform desired updates, potentially broadcast the service use notificationmanager
/** NEED TO BROADCAST INTENT VIA sendBroadCast(intent); */
Intent intent = new Intent(LOCATION_UPDATE);
//Put extras here if desired
intent.putExtra(ACCURACY, locationVal.getAccuracy()); // float double double long int
intent.putExtra(LATITUDE, locationVal.getLatitude());
intent.putExtra(LONGITUDE, locationVal.getLongitude());
intent.putExtra(TIMESTAMP, locationVal.getTime());
intent.putExtra(ALTITUDE,locationVal.getAltitude());
intent.putExtra(NUM_SATELLITES,0);/////////////****TEMP
sendBroadcast(intent); //broadcasting update. need to create a broadcast receiver and subscribe to LOCATION_UPDATE
Log.i("service","made it through onprogress update");
}
/** Custom methods */
private void cancelVal(){ //Called from activity by stopService(intent) --(which calls in service)--> onDestroy() --(which calls in asynctask)--> cancelVal()
trueVal = false;
locationManager.removeUpdates(locationListener);
}
private void handleLocationUpdate(Location location){ // Called by locationListener override.
locationVal = location;
publishProgress();
}
}
Related
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 want a background service class that which will get the user current location sends as a notification to the user if the user changes its location then the updated location will sends back to the user as a notification..even if the user close the application then also will receive the notification (the service will trace the location in background even application closed)
currently i am using this service for tracing the location which works if the application in foreground
can u pls. help me to get out of this i am struggling for 4 hours
in your activity unlike the one that you are using make your buttons start and stop the service and it will run in the background unless the user reopens the app and stops it
Intent i = new Intent(MainActivity.this,gpsservice.class);
startService(new Intent(i));
or to stop
Intent j = new Intent(MainActivity.this,gpsservice.class);
stopService(new Intent(j));
use this service
public class gpsservice extends Service{
private LocationManager locationManager;
MyLocationListener locationListenerp;
public gpsservice() {
}
#Override
public IBinder onBind(Intent intent) {
// TODO Auto-generated method stub
return null;
}
#Override
public void onCreate() {
locationManager = (LocationManager)
getSystemService(Context.LOCATION_SERVICE);
locationListenerp = new MyLocationListener();
locationManager.requestLocationUpdates(
LocationManager.GPS_PROVIDER, 5000, 10, locationListenerp);
}
#Override
public void onDestroy() {
locationManager.removeUpdates(locationListenerp);
}
#Override
public void onStart(Intent intent, int startid) {
Toast.makeText(this, "location Service Started", Toast.LENGTH_LONG).show();
}
public class MyLocationListener implements LocationListener {
#Override
public void onLocationChanged(Location location) {
Toast.makeText(getApplicationContext(), "I was here", Toast.LENGTH_LONG).show();
}
#Override
public void onProviderDisabled(String s) {
}
#Override
public void onProviderEnabled(String s) {
}
#Override
public void onStatusChanged(String arg0, int arg1, Bundle arg2) {
// TODO Auto-generated method stub
}
}
}
I want to stop LocationListener, but using a Log, I´ve found out that my service is still running after removeUpdates() method (When the location changes, it´s inserted into my log). Do you know where the problem is? Thanks in advance.
public class MyService extends Service implements LocationListener {
private final static String TAG = "MyService";
LocationManager lm;
public MyService() {
}
....//Other methods here
public void onLocationChanged(Location loc) {
Log.d(TAG, loc.toString());
if(/*A condition, which has to stop the service when it´s time*/)
{
lm.removeUpdates(this);
lm = null;
}
}
public void subscribeToLocationUpdates() {
this.lm = (LocationManager)getSystemService(Context.LOCATION_SERVICE);
this.lm.requestLocationUpdates(LocationManager.GPS_PROVIDER, 0, 0, this);
}
#Override
public void onDestroy() {
}
}
I call this service in another Activity, onCreate method:
ComponentName comp = new ComponentName(getPackageName(),
MyService.class.getName());
ComponentName service = startService(new Intent().setComponent(comp));
The Service object and its lifecycle is independent of the state of your location manager. or any other object for that matter.
A service represents a background part of your app. once you are done with it you can call finish() method to end it.
So in your case :
public void onLocationChanged(Location loc) {
Log.d(TAG, loc.toString());
if(/*A condition, which has to stop the service when it´s time*/)
{
lm.removeUpdates(this);
lm = null;
stopSelf(); // end this service
}
}
Please take a look at android's Service documentation to get a general overview of its nature : Android Service
I'm writing a test application which keeps track of the users location. The idea is that i can start a service which then registers for location updates. For now I'm using an IntentService for that.
The service code (which is not working...) looks like that:
public class GpsGatheringService extends IntentService {
// vars
private static final String TAG = "GpsGatheringService";
private boolean stopThread;
// constructors
public GpsGatheringService() {
super("GpsGatheringServiceThread");
stopThread = false;
}
// methods
#Override
public int onStartCommand(Intent intent, int flags, int startId) {
Log.d(TAG, "onStartCommand()");
return super.onStartCommand(intent, flags, startId);
}
#Override
protected void onHandleIntent(Intent arg0) {
// this is running in a dedicated thread
Log.d(TAG, "onHandleIntent()");
LocationManager locationManager = (LocationManager) getSystemService(LOCATION_SERVICE);
LocationListener locationListener = new LocationListener() {
#Override
public void onStatusChanged(String provider, int status, Bundle extras) {
Log.d(TAG, "onStatusChanged()");
}
#Override
public void onProviderEnabled(String provider) {
Log.d(TAG, "onProviderEnabled()");
}
#Override
public void onProviderDisabled(String provider) {
Log.d(TAG, "onProviderDisabled()");
}
#Override
public void onLocationChanged(Location location) {
Log.d(TAG, "onLocationChanged()");
}
};
locationManager.requestLocationUpdates(LocationManager.GPS_PROVIDER, 0, 0, locationListener);
while (!stopThread) {
try {
Log.d(TAG, "Going to sleep...");
Thread.sleep(1500);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
#Override
public void onDestroy() {
super.onDestroy();
Log.d(TAG, "onDestroy()");
stopThread = true;
}
}
Currently the only thing which happens is the output of "Going to sleep...". I need some mechanism which keeps the thread alive (because else the listener is not reachable anymore for status updates) and doesnt waste cpu time (I think busy looping is not the preferred way).
Even if there are tons of other ways how to realize the application behaviour (logging of gps coordinates) I am interested in a solution to this way to learn a technique to solve problems of this nature!
How do I keep the Thread of an IntentService alive?
You don't. You do not use IntentService in a scenario like this.
I need some mechanism which keeps the thread alive (because else the listener is not reachable anymore for status updates) and doesnt waste cpu time (I think busy looping is not the preferred way)
No, in this case a Service is fine, because you control when the service is going away, you control the lifetime of any threads you create, etc. IntentService is unsuitable for your intended purpose, because it controls when the service is going away and it controls the lifetime of the threads.
Consider using a remote service. It worked for me.
I implemented Android service for listening user location:
public class ListenLocationService extends Service {
IBinder mBinder = new LocalBinder();
public interface ILocationService {
Location userLocation = new Location("");
public void StartListenLocation();
public void StopListenLocation();
public Location getUserLocation();
}
LocationManager locationManager;
LocationListener locationListener;
public class LocalBinder extends Binder implements ILocationService{
public void StopListenLocation(){
//so many attempts to stop service and no one helped
locationManager.removeUpdates(locationListener);
locationListener = null;
stopSelf();
}
public void StartListenLocation()
{
locationManager = (LocationManager)ListenLocationService.this.getSystemService(Context.LOCATION_SERVICE);
locationListener = new LocationListener() {
public void onStatusChanged(String provider, int status, Bundle extras) {
}
public void onProviderEnabled(String provider) {
}
public void onProviderDisabled(String provider) {
}
public void onLocationChanged(Location location) {
userLocation.set(location);
}
};
//if I have only one requestLocationUpdates situation is the same
locationManager.requestLocationUpdates(LocationManager.NETWORK_PROVIDER,
400, 1, locationListener);
locationManager.requestLocationUpdates(LocationManager.GPS_PROVIDER,
400, 1, locationListener);
}
public Location getUserLocation(){
return userLocation;
}
}
#Override
public IBinder onBind(Intent intent) {
return mBinder;
}
}
I'm binding to this service in two activities. In first activity I'm just launching service:
private ServiceConnection mConnection = new ServiceConnection() {
public void onServiceConnected(ComponentName className,
IBinder service) {
mService = (ILocationService) service;
mService.StartListenLocation();
}
public void onServiceDisconnected(ComponentName arg0) {
Log.d("LOG","onServiceDisconnected");
}
};
public void onCreate(Bundle savedInstanceState) {
...
Intent intent = new Intent(this, ListenLocationService.class);
bindService(intent, mConnection, Context.BIND_AUTO_CREATE);
...
}
#Override
public void onStop(){
super.onStop();
unbindService(mConnection);
mService.StopListenLocation();
}
If I launch in my app only first activity and the close it then service stops - GPS mark disappear from device screen.
However if I enter the second activity (where I'm getting userLocation) and after this close both(using Android back button), then GPS mark still on my screen!
Code from second activity:
private ServiceConnection mConnection = new ServiceConnection() {
public void onServiceConnected(ComponentName className,
IBinder service) {
mService = (ILocationService) service;
userLocation = mService.getUserLocation();
}
public void onServiceDisconnected(ComponentName arg0) {
}
};
#Override
public void onCreate(Bundle savedInstanceState) {
...
Intent intent = new Intent(this, ListenLocationService.class);
bindService(intent, mConnection, Context.BIND_AUTO_CREATE);
...
}
#Override
public void onStop(){
super.onStop();
unbindService(mConnection);
mService.StopListenLocation();
}
You can see that I wrote in both onStop() methods not only unbindService (initially I thought that it'll be enough) but I'm calling StopListenLocation function with this code:
locationManager.removeUpdates(locationListener);
locationListener = null;
stopSelf();
It stops service if only first activity was bound to it. However if both activities were bound, service doesn't stop after both onStop(). I used Log.d to get sure that all methods are called: onStop(), stopListenLocation(), onBind() etc. The only thing is that onServiceDisconnected() is not called ever.
I suppose situation is that my service starts another system service for listening location. I stop my service, but this system service that controls GPS continue to work despite of locationManager.removeUpdates(locationListener);. Maybe I'm mistaken in my suggestion.
How can I stop GPS where both activities are stopped?
BIND_AUTO_CREATE doesn't necessarily mean that the service will terminate itself when there are no connections, it just means that it's the first thing on the chopping block if the system needs resources. If the system is not resource starved, it will let your service continue to run, since, if your activity wants the service again, it is less expensive time-wise to bind to an existing instance than to create it from scratch.
In short, it will keep 'running', but don't worry about it - it's not consuming anything that is needed elsewhere.
EDIT: Also note that just because you have unbound from the service does not mean that it will interrupt any running processing tasks that the service is handling asynchronously. All that's happened is you've told the OS that you aren't interested in the results anymore. You must explicitly stop any running tasks before disconnecting from the service or that task will continue to consume CPU time