I need to have a Service running in Android that stores a value to database every so often. How often is based on user preferences, and also if other events have happened, which can be as often as 30 seconds or up to 30 minutes.
This is not something that is hidden from the user and in fact the user should probably be aware its running. As such I think a foreground service is probably the best approach.
I have a foreground service running, with a TimerTask that calculates how often it needs to fire. That Service is 'sticky' so it should stick around and it low on resources the OS should start it back up after a while.
My problem is that the TimerTask seems to stop running after a while when the the app is backgrounded.
Here is my service:
public class TimerService extends Service {
private static final String LOG_NAME = TimerService.class.getName();
private Timer timer;
private final Handler timerHandler = new Handler();
#Override
public void onCreate() {
super.onCreate();
Notification notification = new NotificationCompat.Builder(this, "MY_APP_CHANNEL_ID")
.setContentTitle("My Timer Service")
.setContentText("Background timer task")
.setSmallIcon(R.drawable.timer)
.build();
startForeground(1, notification);
}
#Override
public int onStartCommand(Intent intent, int flags, int startId) {
startTimer();
return START_STICKY;
}
#Override
public void onDestroy() {
super.onDestroy();
stopTimer();
}
#Override
public IBinder onBind(Intent intent) {
return null;
}
private void stopTimer() {
if (timer != null) {
timer.cancel();
timer = null;
}
}
private void startTimer() {
stopTimer();
timer = new Timer();
long frequency = // calculate frequency
long delay = // calculate delay
timer.scheduleAtFixedRate(new MyTimerTask(), delay, frequency);
}
private void saveToDatabase() {
// Save some stuff to the database...
if (some condition) {
// might need to reschedule timer delay and frequency.
startTimer();
}
}
private class MyTimerTask extends TimerTask {
#Override
public void run() {
timerHandler.post(new Runnable() {
#Override
public void run() {
onTimerFire();
}
});
}
private void onTimerFire() {
try {
saveToDatabase();
} catch (Exception e) {
Log.e(LOG_NAME, "Error in onTimerFire", e);
}
}
}
}
Should this work? IE can I have a simple Timer in a foreground Service that fires continuously until that service is stopped? If so is there a bug in my code?
I chose a Timer to try to keep it simple, I only ever need one timer running and I wanted it to be able to reschedule easily. I do realize that I could try a Handler, ScheduledThreadPoolExecutor, or even an AlarmManager. I thought an AlarmManager might be overkill and a drain on resources if it is firing a ton. Not to mention rescheduling.
Why won’t it run in the background?
It is running in the background. It is not running when the device is asleep, as the CPU is powered down. In Android, "background" simply means "has no foreground UI" (activity, service with a foreground Notification).
I need to have a Service running in Android that stores a value to database every so often. How often is based on user preferences, and also if other events have happened, which can be as often as 30 seconds or up to 30 minutes.
What you want has not been practical on Android since 6.0.
I thought an AlarmManager might be overkill and a drain on resources if it is firing a ton.
That is true. However, the only way to get your existing code to work would be for you to acquire a partial WakeLock, thereby keeping the CPU running forever. This will be orders of magnitude worse for power than is AlarmManager. And AlarmManager is bad enough that each Android release, starting with 6.0, has made it progressively more difficult to use AlarmManager (or JobScheduler, or Timer and a wakelock) to do anything reliably.
You are going to need to learn what Android is and is not capable of with respect to background processing, then adjust your product plans accordingly. That subject is way too long for a Stack Overflow answer.
Here is a set of slides from a presentation that I delivered last year on this subject, with Android 8.0 in mind (use Space to advance to the next slide). You might also read:
My thoughts on Android P DP2, particularly "What’s New in the War on Background Processing"
This preview of one of my book chapters, where the section on Android 8.0 and its phase in "The War on Background Processing" happens to be included
Wakelock and doze mode
IMHO, writing an app that relies upon periodic background processing is a very risky venture nowadays.
You should use ScheduledExecutorService for the same. There can be many ways to schedule background task like Alarm Manager, JobDispatcher, Sync Adapter, Job Scheduler. I will suggest ScheduledExecutorService over them.
I have one good example of using ScheduledExecutorService in service. (Currently using in highly optimised location sync service)
import android.app.Service;
import android.content.Intent;
import android.os.IBinder;
import android.support.annotation.Nullable;
import java.util.concurrent.Executors;
import java.util.concurrent.ScheduledExecutorService;
import java.util.concurrent.TimeUnit;
/**
* Created by KHEMRAJ on 1/29/2018.
*/
public class SyncService extends Service {
private Thread mThread;
ScheduledExecutorService worker;
private static final int SYNC_TIME = 60 * 1000; // 60 seconds
#Override
public int onStartCommand(#Nullable Intent intent, int flags, int startId) {
startSyncService();
return START_STICKY;
}
#Override
public void onDestroy() {
super.onDestroy();
stopThread();
}
#Nullable
#Override
public IBinder onBind(Intent intent) {
return null;
}
private void stopThread() {
worker = null;
if (mThread != null && mThread.isAlive()) mThread.interrupt();
}
private void startSyncService() {
if (worker == null) worker = Executors.newSingleThreadScheduledExecutor();
if (mThread == null || !mThread.isAlive()) {
mThread = new Thread(new Runnable() {
#Override
public void run() {
saveToDb();
if (worker != null) {
worker.schedule(this, SYNC_TIME, TimeUnit.MILLISECONDS);
}
}
});
mThread.start();
}
}
private void saveToDb() {
// TODO: 5/15/2018
}
}
Related
I'm developing a chat application, For getting new messages in real-time we use a foreground service. (because of some situation we can't use FCM)
To be confident that clients are connected to the server, We send a ping to server every 1 minute with JobScheduler. Now we have a battery usage problem.
It's better to use CountDownTimer like bellow code in our foreground service :
CountDownTimer countDownTimerPingPeriodic;
public static boolean isPinging;
public void pingPeriodic(boolean fromService) {
if (countDownTimerPingPeriodic != null) {
countDownTimerPingPeriodic.cancel();
countDownTimerPingPeriodic = null;
}
new Handler(Looper.getMainLooper()).post(new Runnable() {
#Override
public void run() {
long future = 75000;
countDownTimerPingPeriodic =
new CountDownTimer(60000, 60000) {
#Override
public void onTick(long l) {
}
#Override
public void onFinish() {
sendPing(false);
pingPeriodic(false);
}
};
isPinging = true;
countDownTimerPingPeriodic.start();
}
});
}
or it's better to use job service like bellow (Now we use bellow code and send ping in onStartJob):
public class ScheduleConnectionJob extends JobService {
private static final String TAG = "ScheduleConnectionJob";
private int i = 0;
#Override
public int onStartCommand(Intent intent, int flags, int startId) {
return Service.START_STICKY;
}
#Override
public boolean onStartJob(JobParameters params) {
//here I will send a ping to the server
jobFinished(params, true);
Util.scheduleJob(getApplicationContext()); // reschedule the job
return true;
}
#Override
public boolean onStopJob(JobParameters params) {
Util.scheduleJob(getApplicationContext());
return true;
}
#Override
public void onDestroy() {
super.onDestroy();
Util.scheduleJob(getApplicationContext());
}}
And to call and repeat this service We use bellow code to repeat every 1 minute:
public class Util {
public static final long MinimumSchadulePeriodic = 15 * 60 * 1000 ;
// schedule the start of the service every 10 - 30 seconds
public static void scheduleJob(Context context) {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
ComponentName serviceComponent = new ComponentName(context, ScheduleConnectionJob.class);
JobInfo.Builder builder = new JobInfo.Builder(0, serviceComponent);
FileLog.i("Util:",
Thread.currentThread().getStackTrace()[2].getLineNumber() + " " +
"scheduleJob:scheduleJob");
builder.setMinimumLatency(MinimumSchadulePeriodic); // wait at least
builder.setOverrideDeadline(60 * 1000); // maximum delay
builder.setRequiredNetworkType(JobInfo.NETWORK_TYPE_ANY); // require unmetered network
JobScheduler jobScheduler = (JobScheduler) context.getSystemService(Context.JOB_SCHEDULER_SERVICE);
if (jobScheduler != null) {
jobScheduler.schedule(builder.build());
}
}
}}
You can also use WorkManager if it will be better in your case instead of JobScheduler.
The WorkManager API makes it easy to schedule deferrable, asynchronous tasks that are expected to run even if the app exits or device restarts.
Checkout this official documentation for further information ::
https://developer.android.com/topic/libraries/architecture/workmanager/
Also read this article https://medium.com/androiddevelopers/introducing-workmanager-2083bcfc4712
If you don't support below SDK 14 you can use workmanager. Otherwise see this guide to read about all the options.
Some extra resources on battery management: Doze and standby, power management restrictions, Analyzing power usage, Excessive wake-ups, Excessive network usage in background
Hope this helps you along a bit. I have to say that having your app ping the backend every minute seems a bit much. Unless its vital that your users receive their messages the instant they get send, it might be better to atleast bump that down to 5 or 10 minutes in background.
I want a best consistent solution to call an api to update current location in every 2 minutes on Nougat and higher version. The process should not be terminated even when the app is killed or closed.
Thanks in advance
Create a services:
public class MyServices extends Service {
#Override
public IBinder onBind(Intent intent) {
return null;
}
#Override
public void onCreate() {
super.onCreate();
startService(new Intent(this,MyServices.class));
Timer t = new Timer();
final Handler handler = new Handler();
// Timer task makes your service will repeat after every 20 Sec.
TimerTask doAsynchronousTask = new TimerTask() {
#Override
public void run() {
handler.post(new Runnable() {
public void run() {
//Do network call here
}
});
}
};
//Starts after 20 sec and will repeat on every 20 sec of time interval.
t.schedule(doAsynchronousTask, 3000,3000); // 20 sec timer
}
#Override
public int onStartCommand(Intent intent, int flags, int startId) {
return START_STICKY;
}
}
Register the service in menifest
<service android:name=".MyServices" />
Start the service in your activity
Intent intent = new Intent(this, MyServices.class);
startService(intent);
if version > N use this
startForegroundService(intent);
Create a service and update from there.
Service will not stop after closing the application but it will get stopped if the application is force stopped.
And also if your app goes to doze mode your app cannot use Internet or GPS service from the background.
You should check out WorkManager to schedule any kind of work you want your app to do.
I'm writing an app which should collect some sensor data every 10 seconds or so and write them to disk.
So far, I have an Activity which starts a service. The service has a runnable, which uses a handler to run my task periodically via handler.postDelayed(). See below for the (shortened) code.
So far, this works fine as long as the device is active. As soon as the device goes into idle, it doesn't run my task until it wakes up again.
So, my question is how to run my task ALWAYS.
With setExactAndAllowWhileIdle(), the AlarmManager seems to offer exactly what I need, but...
To reduce abuse, there are restrictions on how frequently these alarms will go off for a particular application. Under normal system operation, it will not dispatch these alarms more than about every minute (at which point every such pending alarm is dispatched); when in low-power idle modes this duration may be significantly longer, such as 15 minutes.
Battery life has just a minor priority, though not being awake the entire time would be fine. (Not sure if android can be awake for just a second or so)
MyActivity
...
public void onStartService(View view) {
Intent i= new Intent(getBaseContext(), MyAppService.class);
getBaseContext().startService(i);
}
public void onStopService(View view) {
stopService(new Intent(getBaseContext(), MyAppService.class));
}
....
MyService
public class MyAppService extends Service {
MyRunnable mr;
#Override
public int onStartCommand(Intent intent, int flags, int startId) {
mr= new MyRunnable(getApplicationContext() );
mr.Start();
return Service.START_NOT_STICKY;
}
#Override
public void onDestroy() {
super.onDestroy();
mr.Stop();
}
#Override
public IBinder onBind(Intent intent) {
// TODO: Return the communication channel to the service.
throw new UnsupportedOperationException("Not yet implemented");
}
}
MyRunnable
public class MyRunnable implements Runnable{
// context is needed for sensorListener (?)
private Context myContext;
private Handler handler;
public MyRunnable(Context c){
myContext=c;
handler= new Handler();
}
public void Start(){
run();
}
public void Stop(){
handler.removeCallbacks(this);
// some clean-up
}
#Override
public void run() {
//acquire and write to file some sensor data
handler.postDelayed(this, 10000);
}
}
i think what you are looking for is STICKY SERVICE.
Officail Docs: If the system kills the service after onStartCommand() returns, recreate the service and call onStartCommand(), but do not redeliver the last intent. Instead, the system calls onStartCommand() with a null intent, unless there were pending intents to start the service, in which case, those intents are delivered. This is suitable for media players (or similar services) that are not executing commands, but running indefinitely and waiting for a job.
you just need to pass a flag at the time of calling the service.
What is the recommended approach for checking for new data regardless if the app is in the foreground or background? I am wondering which Android API people are typically using to do this. There seems to be a few ways to achieve my goal, and I want to make sure I'm on the right path.
I have something put together which uses AlarmManager.SetInexactRepeating() to call an IntentService which does the sync and inserts/updates data in the database. This works while the app is in the foreground and background, but if I force stop the app then I keep seeing "Unfortunately, has stopped working" messages when the AlarmManager alarm would've triggered. In this case, I only care about checking for new data only when the app is running in the foreground or background.
My first thought is to detect when the app is force closed, and stop the alarm, but that does not seem possible. So I am asking here, is my approach wrong? If so, which approach is used to perform some periodic task regardless if the phone is in the foreground or background? The problem with the AlarmManager solution I am using is the alarms continue to fire even when the app is closed.
If your idea is to check if your API has new data and perform a background sync to your local database or other data storage, I think you would like to take a look at this:
Creating a Sync Adapter
Running a Sync Adapter
The Sync adapter is the recommended way of achieving this in Android. The pros of using it are multiple:
Optimisations out of the box - the OS bundles calls, uses the most appropriate windows to run the sync adapter at a minimal bandwidth and battery cost
The lifecycle of your background sync component is managed internally by the OS
Observers can be notified when data has been changed so the UI can be updated easily
Multiple ways of running the sync - at intervals, automatically with the OS message to keep TCP/IP connections open or on demand
However, implementing this requires some things, that can cause a bit of a pain at first:
It is mandatory that the adapter works with a ContentProvider
Sync Adapters use Account for authentication. If this is not needed, a Stub has to be provided
For backgrounding on Android usually you use even a Service that can run alone and independently from the App or a Bounded service that takes and returns data from the App. A complete reference on backgrounding can be found here
Using a Service is the right way to go. Have your app start the Service and it will continue running while the app is in the foreground or the background. Then, if you want to kill the Service when your app closes, you could just call stopService(yourServiceIntent); from the onDestroy() override in your app's activity. That should effectively shut down the service when the app closes.
So some sample code of how this works (taken from the Services docs)...
The Service (just Logs a message every 1 second for 60 seconds):
public class MyService extends Service {
private Looper mServiceLooper;
private ServiceHandler mServiceHandler;
// Handler that receives messages from the thread
private final class ServiceHandler extends Handler {
public ServiceHandler(Looper looper) {
super(looper);
}
#Override
public void handleMessage(Message msg) {
long endTime = System.currentTimeMillis() + 60*1000;
while (System.currentTimeMillis() < endTime) {
synchronized (this) {
try {
wait(1000);
Log.d("SERVICE", "The service is still running.");
} catch (Exception e) {
e.printStackTrace();
}
}
}
stopSelf(msg.arg1);
}
}
#Override
public void onCreate() {
HandlerThread thread = new HandlerThread("ServiceStartArguments", Process.THREAD_PRIORITY_BACKGROUND);
thread.start();
mServiceLooper = thread.getLooper();
mServiceHandler = new ServiceHandler(mServiceLooper);
}
#Override
public int onStartCommand(Intent intent, int flags, int startId) {
Message msg = mServiceHandler.obtainMessage();
msg.arg1 = startId;
mServiceHandler.sendMessage(msg);
return START_NOT_STICKY;
}
#Override
public IBinder onBind(Intent intent) {
return null;
}
#Override
public void onDestroy() {
}
}
And in your activity you would do something like:
public class MainActivity extends AppCompatActivity {
Intent serviceIntent;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
serviceIntent = new Intent(this, MyService.class);
startService(serviceIntent);
}
#Override
protected void onDestroy() {
stopService(serviceIntent);
super.onDestroy();
}
I am working on an app that will relay information about its location to a remote server. I am intending to do it by doing a simple HTTP post to the web-server and all is simple and fine.
But according to the spec, the app needs to execute itself from time to time, lets say once in every 30 mins. Be independent of the interface, meaning which it needs to run even if the app is closed.
I looked around and found out that Android Services is what needs to be used. What could I use to implement such a system. Will the service (or other mechanism) restart when the phone restarts?
Thanks in advance.
Create a Service to send your information to your server. Presumably, you've got that under control.
Your Service should be started by an alarm triggered by the AlarmManager, where you can specify an interval. Unless you have to report your data exactly every 30 minutes, you probably want the inexact alarm so you can save some battery life.
Finally, you can register your app to get the bootup broadcast by setting up a BroadcastReceiver like so:
public class BootReceiver extends BroadcastReceiver {
#Override
public void onReceive(Context context, Intent intent) {
if (intent.getAction().equals(Intent.ACTION_BOOT_COMPLETED)) {
// Register your reporting alarms here.
}
}
}
You'll need to add the following permission to your AndroidManifest.xml for that to work. Don't forget to register your alarms when you run the app normally, or they'll only be registered when the device boots up.
<uses-permission android:name="android.permission.RECEIVE_BOOT_COMPLETED"/>
Here is a semi-different way to keep the service going forever. There is ways to kill it in code if you'd wish
Background Service:
package com.ex.ample;
import android.app.Service;
import android.content.*;
import android.os.*;
import android.widget.Toast;
public class BackgroundService extends Service {
public Context context = this;
public Handler handler = null;
public static Runnable runnable = null;
#Override
public IBinder onBind(Intent intent) {
return null;
}
#Override
public void onCreate() {
Toast.makeText(this, "Service created!", Toast.LENGTH_LONG).show();
handler = new Handler();
runnable = new Runnable() {
public void run() {
Toast.makeText(context, "Service is still running", Toast.LENGTH_LONG).show();
handler.postDelayed(runnable, 10000);
}
};
handler.postDelayed(runnable, 15000);
}
#Override
public void onDestroy() {
/* IF YOU WANT THIS SERVICE KILLED WITH THE APP THEN UNCOMMENT THE FOLLOWING LINE */
//handler.removeCallbacks(runnable);
Toast.makeText(this, "Service stopped", Toast.LENGTH_LONG).show();
}
#Override
public void onStart(Intent intent, int startid) {
Toast.makeText(this, "Service started by user.", Toast.LENGTH_LONG).show();
}
}
Here is how you start it from your main activity or wherever you wish:
startService(new Intent(this, BackgroundService.class));
onDestroy() will get called when the application gets closed or killed but the runnable just starts it right back up.
I hope this helps someone out.
The reason why some people do this is because of corporate applications where in some instances the users/employees must not be able to stop certain things :)
http://i.imgur.com/1vCnYJW.png
EDIT
Since Android O (8.0) you have to use JobManager for scheduled tasks. There is a library called Android-Job by Evernote which will make periodic background work a breeze on all Android versions. I have also made a Xamarin Binding of this library.
Then all you need to do is the following:
In your application class:
public class MyApp extends Application {
#Override
public void onCreate() {
super.onCreate();
JobManager.create(this).addJobCreator(new MyJobCreator());
}
}
Create the following two classes YourJobCreator and YourSyncJob(Where all the work will be done. Android allocates time for all the background jobs to be run. For android versions < 8.0 it will still run with an Alarm manager and background service as per normal)
public class MyJobCreator implements JobCreator {
#Override
#Nullable
public Job create(#NonNull String tag) {
switch (tag) {
case MySyncJob.TAG:
return new MySyncJob();
default:
return null;
}
}
}
public class MySyncJob extends Job {
public static final String TAG = "my_job_tag";
#Override
#NonNull
protected Result onRunJob(Params params) {
//
// run your job here
//
//
return Result.SUCCESS;
}
public static void scheduleJob() {
new JobRequest.Builder(MySyncJob.TAG)
.setExecutionWindow(30_000L, 40_000L) //Every 30 seconds for 40 seconds
.build()
.schedule();
}
}
You should schedule your service with alarm manager, first create the pending intent of service:
Intent ii = new Intent(getApplicationContext(), MyService.class);
PendingIntent pii = PendingIntent.getService(getApplicationContext(), 2222, ii,
PendingIntent.FLAG_CANCEL_CURRENT);
Then schedule it using alarm manager:
//getting current time and add 5 seconds to it
Calendar cal = Calendar.getInstance();
cal.add(Calendar.SECOND, 5);
//registering our pending intent with alarmmanager
AlarmManager am = (AlarmManager) getSystemService(ALARM_SERVICE);
am.set(AlarmManager.RTC_WAKEUP,cal.getTimeInMillis(), pi);
this will launch your service after 5 seconds of current time. You can make your alarm repeating.
You can use Alarm Manager to start Service at specified time and then repeat alarm in specified interval. When alarm goes on you can start service and connect to server and make what you want