Custom service class with a ThreadPoolExecutor killed when app is off - android

I need to execute multipe tasks in parallel inside a custom service to get these working :
- Location service and activity recognition API.
- Geofence API and REST API calls.
I'm new to threads in java and android, and i found that the best way to implement this is to use a ThreadPoolExecutor instead of making my own thread classes and dealing with all the Handler Looper stuff.
When i execute my app, the service starts, Location updates and activity updates works fine inside a thread. but, when i close the app, the service restarts (when return START_STICKY;) and the thread is not working anymore.When (return START_NOT_STICKY;), the service disappears.
(In my case, i can't use startforeground())
I'm using this library(smart-location-lib) for location and activity updates.
- Here's my custom service code :
public class LocationService extends Service {
private ThreadPoolExecutor mDecodeThreadPool;
private BlockingQueue<Runnable> mDecodeWorkQueue;
private int NUMBER_OF_CORES = Runtime.getRuntime().availableProcessors();
private final int KEEP_ALIVE_TIME = 1;
private final TimeUnit KEEP_ALIVE_TIME_UNIT = TimeUnit.SECONDS;
public LocationService () {
}
#Override
public void onCreate() {
super.onCreate();
Toast.makeText(this, "Location services created", Toast.LENGTH_SHORT).show();
mDecodeWorkQueue = new LinkedBlockingQueue<Runnable>();
mDecodeThreadPool = new ThreadPoolExecutor(
NUMBER_OF_CORES * 2, // Initial pool size
NUMBER_OF_CORES * 2, // Max pool size
KEEP_ALIVE_TIME,
KEEP_ALIVE_TIME_UNIT,
mDecodeWorkQueue);
}
#Override
public int onStartCommand(Intent intent, int flags, int startId) {
Toast.makeText(this, "Location services started", Toast.LENGTH_SHORT).show();
mDecodeThreadPool.execute(new LocationRunnable(getApplicationContext()));
return START_STICKY;
}
#Override
public void onLowMemory() {
super.onLowMemory();
Log.v("LOW MEMORY", "|||||||||||||||||||||||||||||||||||||");
}
#Override
public IBinder onBind(Intent intent) {
throw new UnsupportedOperationException("Not yet implemented");
}
#Override
public void onDestroy() {
Toast.makeText(this, "Location services stopped", Toast.LENGTH_LONG).show();
mDecodeThreadPool.shutdown();
mDecodeThreadPool.shutdownNow();
super.onDestroy();
}
}
- Here's my Runnable class code :
public class LocationRunnable implements Runnable, OnLocationUpdatedListener, OnActivityUpdatedListener {
SmartLocation smartLocation;
public LocationRunnable(Context ctx) {
smartLocation = new SmartLocation.Builder(ctx).logging(true).build();
}
#Override
public void run() {
Log.v("THREAD", "THREAD STARTED");
startLocation();
}
private void startLocation() {
smartLocation.location().start(this);
smartLocation.activity().start(this);
}
#Override
public void onActivityUpdated(DetectedActivity detectedActivity) {
if (detectedActivity != null) {
Log.v("ACTIVITY", "ACTIVITY UPDATED");
} else {
Log.v("ACTIVITY", "NULL");
}
}
int i = 0;
#Override
public void onLocationUpdated(Location location) {
Log.v("LOCATION", "LOCATION UPDATED" + i++);
}
private String getNameFromType(DetectedActivity activityType) {
switch (activityType.getType()) {
case DetectedActivity.IN_VEHICLE:
return "in_vehicle";
case DetectedActivity.ON_BICYCLE:
return "on_bicycle";
case DetectedActivity.ON_FOOT:
return "on_foot";
case DetectedActivity.STILL:
return "still";
case DetectedActivity.TILTING:
return "tilting";
default:
return "unknown";
}
}
}
I'm not really sure if this is the right or the best way to get what i need.
Any help is greatly appreciated !

I realize the question is old, but it might be of help to others.
I think it is due to the fact that the code from Runnable.run() exits immediately, thereby ending the parent thread, so that the changes in location no longer have an object to be posted to.
smartLocation.location().start(this); // this <-- is the Runnable
And the reason you get update until restart might be due to garbage collection not clearing up the no longer used Runnable object or some existing reference to it within your code.

Related

Run a service in background continuously

Run a service in background continuously. For example, a service has to be kicked off which will display a toast message 20 seconds once even if the app is closed.
public class AppService extends IntentService {
public int onStartCommand(Intent intent, int flags, int startId) {
return START_STICKY;
}
public AppService() {
super("AppService");
}
#Override
protected void onHandleIntent(Intent workIntent) {
Toast.makeText(getApplicationContext(), "hai", Toast.LENGTH_SHORT).show();
SystemClock.sleep(20000);
}
}
Below code works for me...
public class AppService extends Service {
#Override
public IBinder onBind(Intent intent) {
// TODO Auto-generated method stub
return null;
}
#Override
public void onCreate() {
Toast.makeText(this, " MyService Created ", Toast.LENGTH_LONG).show();
}
#Override
public int onStartCommand(Intent intent, int flags, int startId) {
Toast.makeText(this, " MyService Started", Toast.LENGTH_LONG).show();
return START_STICKY;
}
}
Accepted answer will not work on from Android 8.0 (API level 26), see the android's background limitations here
Modification in Accepted Answer:
1: You have to invoke the service's startForeground() method within 5 seconds after starting the service. To do this, you can call startForeground() in onCreate() method of service.
public class AppService extends Service {
....
#Override
public void onCreate() {
startForeground(9999, Notification())
}
....
}
2: You must call startForegroundService() instead of startService() by checking API level from where you want to start the service.
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
context.startForegroundService(intent);
} else {
context.startService(intent);
}
This code work for me..
public class ServiceClass extends Service {
public static final int notify = 300000; //interval between two services(Here Service run every 5 Minute)
private Handler mHandler = new Handler(); //run on another Thread to avoid crash
private Timer mTimer = null; //timer handling
#Override
public IBinder onBind(Intent intent) {
throw new UnsupportedOperationException("Not yet implemented");
}
#Override
public void onCreate() {
if (mTimer != null) // Cancel if already existed
mTimer.cancel();
else
mTimer = new Timer(); //recreate new
mTimer.scheduleAtFixedRate(new TimeDisplay(), 0, notify); //Schedule task
}
#Override
public void onDestroy() {
super.onDestroy();
mTimer.cancel(); //For Cancel Timer
Log.d("service is ","Destroyed");
}
//class TimeDisplay for handling task
class TimeDisplay extends TimerTask {
#Override
public void run() {
// run on another thread
mHandler.post(new Runnable() {
#Override
public void run() {
Log.d("service is ","running");
}
});
}
}
}
In your manifest, where you declare your service, add:
android:process=":processname"
This lets the service run on a separate process and thus it will not be killed with the app.
You can then chose if you want to use foreground. It will show a persistent notification, but reduces the likelihood if the service being killed.
Further, if you want to create a continuously running service, use Service, NOT IntentService. IntentService stops when it is finished doing its action.

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.

Checking status of a service failing because classloader

I have an Activity that starts a service which isn't local. Sometimes I check if is alive to perform actions.
My attempt at the moment was to use a static boolean variable. Reading some posts on SO I found out this not works because each process has it's own classloader.
Iterating over all running services is expensive to do a simple task like this.
Other solutions points out to use AIDL. In a very near future in my service, I'll store a WeakReference for the current running activity to execute it again in case of crash. Assuming for now I just want to check the service' state, is this an expensive solution too?
P.S.: I know it's an ugly solution to not handle exception properly. It's just a try.
EDIT: To clarify what I'm doing I post some code. This is the Service classs:
public class CrashRecover extends Service {
private volatile boolean stop = false;
private Thread backgroundThread;
private Messenger serviceMessenger = null;
private static boolean running = false;
...
#Override
public int onStartCommand(Intent intent, int flags, int startID){
serviceMessenger = new Messenger(new ServiceHandler(serviceLooper));
return START_STICKY;
}
#Override
public void onCreate(){
super.onCreate();
HandlerThread handlerThread = new HandlerThread("CrashRecoverThread", Process.THREAD_PRIORITY_BACKGROUND);
handlerThread.start();
serviceLooper = handlerThread.getLooper();
backgroundThread = new Thread(){
#Override
public void run(){
synchronized(this){
try {
while(!stop){
sleep(500);
}
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
};
running = true;
}
#Override
public void onDestroy(){
super.onDestroy();
try {
Message destroyMessage = Message.obtain();
destroyMessage.arg1 = CrashRecover.DESTROY_SERVICE;
serviceMessenger.send(destroyMessage);
} catch (RemoteException e) {
e.printStackTrace();
}
running = false;
}
#Override
public IBinder onBind(Intent arg0) {
return serviceMessenger.getBinder();
}
public static boolean isRunning(){
return CrashRecover.running;
}
...
private class ServiceHandler extends Handler{
public ServiceHandler(Looper looper){
super(looper);
}
#Override
public void handleMessage(Message message){
switch(message.what){
case REGISTER_CLIENT:
//addActivityToRespawn(null);
//respawnActivity();
Log.i("INFO", "Service is registered");
break;
case UNREGISTER_CLIENT:
activityParams = message.getData();
//respawnActivity();
if(backgroundThread.isAlive()){
stop = true;
}
Log.i("INFO", "Service is unregistered");
break;
case DESTROY_SERVICE:
Log.i("INFO", "Service is destroyed");
break;
default:
super.handleMessage(message);
}
}
}
}
And this is my class when I verify if service is running:
public class Main extends Activity {
private Button serviceButton, crashButton;
private Intent serviceIntent;
private ClientMessageHandler clientHandler;
#Override
public void onCreate(Bundle savedInstanceState) {
...
clientHandler = new ClientMessageHandler();
serviceIntent = new Intent(Main.this, CrashRecover.class);
startService(serviceIntent);
}
...
#Override
public void onBackPressed(){
if(CrashRecover.isRunning()){
Log.i("INFO", "Service is running");
//Execute some actions
}
}
...
}
If you aren't doing this very often then I'd suggest using the "iterate over running services" method. There shouldn't be that many services running on your phone and iterating over them just accesses some internal data structures that Android keeps. Should work just fine.

Run Android services Until App Destroyed

Actually i have to perform some technique in which some particular method will be called after specified time until app destroyed.I Google it and have found services.Using services this work can be performed.I have gone through many Service tutorials so now i can work with services but can anybody tell me how to do this. Should i use services for call particular tack in the background of the activity after specified time?...Thanks....
Edit: I have used following code
public class MyService extends Service {
int count = 0;
#Override
public void onCreate() {
super.onCreate();
}
#Override
public void onStart(Intent intent, int startId) {
super.onStart(intent, startId);
handler.removeCallbacks(updateTimeTask);
handler.postDelayed(updateTimeTask, 1000);
Toast.makeText(this, "Service started................",
Toast.LENGTH_SHORT).show();
}
private Runnable updateTimeTask = new Runnable() {
public void run() {
if (count == 50) {
count = 0;
Tocken_parser tocken = new Tocken_parser();
tocken.tockenParser("1");
Toast.makeText(MyService.this, "coutn===", Toast.LENGTH_SHORT)
.show();
System.out.println("Count ===============");
}
count++;
handler.postDelayed(this, 1000);
}
};
private Handler handler = new Handler();
#Override
public void onDestroy() {
super.onDestroy();
System.out
.println("Service destroyed........................................");
}
#Override
public IBinder onBind(Intent intent) {
return null;
}
}
Its working properly but tell me one thing, how to stop services when activity destroyed.
The answer is YES. Also, the Service that spawned by Activity will be destroyed together; unless, you assign a schedule check on Alarm to wake up your dead Service.

Categories

Resources