How do I keep the Thread of an IntentService alive? - android

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.

Related

Android repeated Service - onCreate called once, onStartCommand called many

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

Service Process - Ram Memory increases with time. How to fix it?

I am making an Android app which runs a simple Service in the background.
Nothing fancy but the service toasts a msg every 5 secs confirming that it is running in the background, even when the App activity is terminated.
But when i checked the task manager, i found that the process is utilizing 4MB of ram initially but later keeps on increasing with time.
I want to know that if there is any way i can stop the extra memory usage and keep it to a bare minimum, since i know i am not doing any heavy work in the background.
Any help will be appreciated!
Thanks.
P.S. I will post the service code below.
public class BgmService extends Service {
public Handler mHandler = new Handler();
public BgmService() {
}
#Override
public IBinder onBind(Intent intent) {
// TODO: Return the communication channel to the service.
throw new UnsupportedOperationException("Not yet implemented");
}
#Override
public void onCreate() {
super.onCreate();
Toast.makeText(this, "Service has started!!!", Toast.LENGTH_SHORT).show();
}
#Override
public int onStartCommand(Intent intent, int flags, int startId) {
mHandler.post(mtask);
return super.onStartCommand(intent, flags, startId);
}
#Override
public void onDestroy() {
super.onDestroy();
Toast.makeText(this, "Service was Killed!!!", Toast.LENGTH_SHORT).show();
mHandler.removeCallbacks(mtask);
}
public Runnable mtask = new Runnable() {
#Override
public void run() {
Toast.makeText(getApplicationContext(), "Service is Running!!!", Toast.LENGTH_SHORT).show();
mHandler.postDelayed(mtask, 4000);
}
};
}
As #PunK_l_RuLz told, your Runnable is getting created after every 4000 mili seconds. So, you can create a subclass of Runnable and use single object of this class for every Toast :
public class PostRunnable extends Runnable {
#Override
public void run() {
Toast.makeText(getApplicationContext(), "Service is Running!!!", Toast.LENGTH_SHORT).show();
mHandler.postDelayed(mRunnable, 4000);
}
}
Use above class like :
PostRunnable mRunnable;
if(mRunnable != null) {
mHandler.post(mRunnable);
} else {
mRunnable = new PostRunnable();
mHandler.post(mRunnable);
}
you are calling the mTask from inside your mTask, every time a new object of Runnable is created and as your Service holds the reference of every runnable object created your memory goes on increasing. I think using a Timer with TimerTask might solve your problem. Hope this helps
Have you tried using a timer instead of a post delay?
It's odd though, I can't see why it would leak.

Service is off when screen is turns off

I am confused a little bit on the behavior of the service.I created a service class which is Emailing my location as soon as the latitude and longitude of My Device is changed.The Service is working perfect when the screen of my phone is on but as soon as the phone screen off the service is not updating me for new locations.I have read somewhere on the SO about wake lock.I don't know how can I implement wake lock on my service and even I don't know whether it will work or not.Please guide me how can I acquire wake lock on my service class
Code for my service class:
public class LocationUpdater extends Service {
private LocationManager lm;
private LocationListener locationListener;
#Override
public IBinder onBind(Intent intent) {
return null;
}
#Override
public int onStartCommand(Intent intent, int flags, int startId) {
Toast.makeText(getApplicationContext(), "Location updater started",Toast.LENGTH_LONG).show();
locationListener = new MyLocationListener();
lm = (LocationManager) getSystemService(Context.LOCATION_SERVICE);
if (!lm.isProviderEnabled(LocationManager.GPS_PROVIDER)) {
lm.requestLocationUpdates(LocationManager.NETWORK_PROVIDER, 0,0,
locationListener);
} else {
lm.requestLocationUpdates(LocationManager.GPS_PROVIDER,0, 0,
locationListener);
lm.requestLocationUpdates(LocationManager.NETWORK_PROVIDER,0, 0,
locationListener);
}
return START_STICKY;
}
#Override
public void onDestroy() {
lm.removeUpdates(locationListener);
super.onDestroy();
}
#Override
public void onCreate() {
Toast.maketext(getApplicationContext,"Updater Serive Created",Toast.LENGTH_LONG).show;
}
private class MyLocationListener implements LocationListener {
#Override
public void onLocationChanged(Location loc) {
if (loc != null) {
String latitude=loc.getLatitude();
Striing longitude=loc.getLongitude();
emailMyLocation(latitude,longitude);
}
}
#Override
public void onStatusChanged(String provider, int status, Bundle extras) {
}
#Override
public void onProviderEnabled(String provider) {
}
#Override
public void onProviderDisabled(String provider) {
}
}
}
This is the service class which is updating the location of my device to my email.Please tell how can I make it work even if the screen is off.
You should check out answer for this question in the following thread: How can I keep my Android service running when the screen is turned off?. Probably, you need a partial WakeLock, which will keep CPU running even when the screen is turned off. You should also check documentation of PowerManager in Android API, which explains behavior of wake locks.
You can aquire the wake lock like this:
Make a Globals class and declare wakelock as static variable
public class Globals {
public static PowerManager.WakeLock wakelock;
}
Now in your service class Declare these:
PowerManager.WakeLock wakeLock ;
PowerManager pm;
Now you can have two functions for wakelocks:
public void acquirewakeLock() {
if(Globals.wakelock!=null){
Globals.wakelock.release();
Globals.wakelock=null;
}
pm = (PowerManager) getSystemService(Context.POWER_SERVICE);
wakeLock = pm.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK,
"TrackerService");
wakeLock.acquire();
Globals.wakelock=this.wakeLock;
}
public void releaseWakelock() {
wakeLock.release();
}
Now in your onCreate method you can quire wakelock with this:
#Override
public void onCreate() {
acquirewakeLock()
}
This will take care of whether CPU is held by other activities and services or not.And you will be able to give cpu to your sevice class.
You can also use
wakelock.acquire(time in milliseconds)
if you know the time your service needs to process. :)

service, that listens for Location Service

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).

Should I create service for GPS tracking APP?

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();
}
}

Categories

Resources