I want to make a background running service (independent of an app) which would download weather data from server periodically every day. I already have code to download data from the server and store it in the database.
What I would like to know is, what is the best way to run the service periodically.
You can Create a Android Intent Service :-
public class BackendService extends IntentService {
public BackendService() {
super("BackendService");
}
#Override
protected void onHandleIntent(Intent intent) {
// Your Download code
}
}
Then set a Alarm Receiver to set the interval in which service will be called.
public void backendscheduleAlarm() {
// Construct an intent that will execute the AlarmReceiver
Intent intent = new Intent(getApplicationContext(), BackendAlarm.class);
// Create a PendingIntent to be triggered when the alarm goes off
final PendingIntent pIntent = PendingIntent.getBroadcast(this, BackendAlarm.REQUEST_CODE,
intent, PendingIntent.FLAG_UPDATE_CURRENT);
// Setup periodic alarm every 1 hour
long firstMillis = System.currentTimeMillis(); // first run of alarm is immediate
int intervalMillis = 3000; //3600000; // 60 min
AlarmManager backendalarm = (AlarmManager) this.getSystemService(Context.ALARM_SERVICE);
backendalarm.setInexactRepeating(AlarmManager.RTC_WAKEUP, firstMillis, intervalMillis, pIntent);
}
And Create a Broadcast Receiver class to call that service:
public class BackendAlarm extends BroadcastReceiver {
public static final int REQUEST_CODE = 12345;
// Triggered by the Alarm periodically (starts the service to run task)
#Override
public void onReceive(Context context, Intent intent) {
Intent i = new Intent(context, BackendService.class);
i.putExtra("foo", "bar");
context.startService(i);
} }
read about Android Services which are mainly made for such background work:
http://developer.android.com/guide/components/services.html
all you need is to start the service on a certain time you set.
Related
So I made an app that upon a button click sets up a repeating task using an Alarm Manager.
In on create:
Intent alarmIntent = new Intent(this, AlarmReceiver.class);
servicePendingIntent = PendingIntent.getBroadcast(this, 0, alarmIntent, 0);
On the button click:
alarmManager = (AlarmManager)getSystemService(Context.ALARM_SERVICE);
firingCal= Calendar.getInstance();
firingCal.setTimeInMillis(System.currentTimeMillis());
firingCal.set(Calendar.HOUR_OF_DAY, 1); // At the hour you want to fire the alarm
firingCal.set(Calendar.MINUTE, 47); // alarm minute
firingCal.set(Calendar.SECOND, 0); // and alarm second
long intendedTime = firingCal.getTimeInMillis();
long interval = 1000 * 60 * 1;
alarmManager.setInexactRepeating(AlarmManager.RTC_WAKEUP, intendedTime, interval, servicePendingIntent);
In the AlarmReceiver class:
public void onReceive(Context context, Intent intent) {
Intent myIntent = new Intent(context, WallpaperService.class);
context.startService(myIntent);
Log.d(TAG,"Am apelat serviciul");
context.stopService(myIntent);
}
And in the WallpaperService class I just make a get request and set an wallpaper.
public class WallpaperService extends Service {
String requestLink="";
boolean requestFinished = false;
public final String TAG = "Service";
public static int SERVICE_ID = 1;
#Override
public void onCreate() {
super.onCreate();
Log.d(TAG,"Wallpaper Service started");
Toast.makeText(WallpaperService.this,"Service started",Toast.LENGTH_LONG);
}
#Override
public int onStartCommand(Intent intent, int flags, int startId) {
Log.d(TAG,"In onStartCommand");
taskToBeRepeated();
stopSelf();
return START_STICKY;
}
.....
}
And the behaviour is that when I start the app and I click the button everything works well the first time the Alarm Manager fires ( With the app in the background). The second time the receiver gets triggered I get the error in the tile. To be more specific :
java.lang.RuntimeException: Unable to start receiver com.example.dailywallpaper.AlarmReceiver: java.lang.IllegalStateException: Not allowed to start service Intent { cmp=com.example.dailywallpaper/.WallpaperService }: app is in background uid UidRecord{3e313bf u0a357 RCVR bg:+1m21s273ms idle change:uncached procs:1 seq(0,0,0)}
What seems to be the problem ? And why is working the first time and then it gives the error? How can I fix it ?
you need to read android official documentation about the policy of using background service or alarms in android 8 and above and adapt your app with this limitations.
I suggest you to read this two articles very carefully :
https://developer.android.com/guide/components/services
https://developer.android.com/about/versions/oreo/background
I'm doing an Android app that requires sending its location frequently, every 1 minute or 2 minutes at the most. For this, I use a JobSchedulerService. I've already managed to make it run more than once every 15 minutes on devices with Android N version by replacing the .setPeriodic() with a .setMinimumLatency(). The fact is that at the beginning it is executed periodically in the established time, but after a while it runs every 7 or 9 minutes approximately.
I have already included the application in the battery saving white list, but didn't work. Is there any way to execute it or a similar service every minute with no restrictions? Doesn't matter how much battery the app spends.
EDIT:
This is what I've tried:
ReceiverService:
public class ReceiverService extends WakefulBroadcastReceiver {
#Override
public void onReceive(Context ctx, Intent intent) {
if (intent.getAction().equals(Intent.ACTION_BOOT_COMPLETED)) {
if (!isMyServiceRunning(ServiceBackground.class, ctx))
startWakefulService(ctx, new Intent(ctx, ServiceBackground.class));
new ServiceAlarmManager(ctx).register();
}
}
private boolean isMyServiceRunning(Class<?> serviceClass,Context context) {
ActivityManager manager = (ActivityManager)context. getSystemService(Context.ACTIVITY_SERVICE);
for (ActivityManager.RunningServiceInfo service : manager.getRunningServices(Integer.MAX_VALUE)) {
if (serviceClass.getName().equals(service.service.getClassName())) {
Log.i("Service already","running");
return true;
}
}
Log.i("Service not","running");
return false;
}
}
The ServiceAlarmManager is exactly the same as #madking said.
You can put your code that sends location in a Service and implement an AlarmManager that periodically checks if your Service is running and restarts it if the Service has been killed by OS. You'll have to implement the AlarmManager using a WakefulBroadcastReceiver.
ReceiverService.java
public class ReceiverService extends WakefulBroadcastReceiver {
#Override
public void onReceive(Context ctx, Intent intent) {
if (!YourService.isRunning()) {
startWakefulService(ctx, new Intent(ctx, YourService.class));
}
new ServiceAlarmManager(ctx).register();
}
}
ServiceAlarmManager.java
public class ServiceAlarmManager {
private Context ctx;
private static final int TIME_INTERVAL = 300 * 1000;
public ServiceAlarmManager(Context context) {
ctx = context;
}
public void register() {
Intent serviceRestarter = new Intent();
serviceRestarter.setAction("someString");
PendingIntent pendingIntentServiceRestarter = PendingIntent.getBroadcast(ctx, 0, serviceRestarter, 0);
AlarmManager alarmManager = (AlarmManager) ctx.getSystemService(ctx.ALARM_SERVICE);
Date now = new Date();
alarmManager.setExactAndAllowWhileIdle(AlarmManager.RTC_WAKEUP, now.getTime() + TIME_INTERVAL, pendingIntentServiceRestarter);
}
}
Also register your BroadcastReceiver in your Manifest.xml file
<receiver android:name=".ReceiverService">
<intent-filter>
<action android:name="someString" />
</intent-filter>
</receiver>
The register() method does two things.
1- Issues a broadcast which is caught by WakefulBroadcastReceiver and restarts the Service if required
2- Sets the next alarm to be invoked to check if the Service has been killed.
This way the service keeps running even if the OS kills it and you'll be able to send location updates periodically.
Note: Though this practice is not recommended as your application will use more battery but you don't seem to care about it as I did not either as some business requirements don't leave us a choice.
I tried this and it works: in the onCreate() of your activity you schedule an Alarm for every minute (setAlarm). Everytime the alarm is triggered, WakefulBroadcastReceiver is called, and that's where we launch our service(s):
private static long INTERVAL_ALARM = 1 * 60 * 1000;
public static void setAlarm(Context context) {
long current_time = Calendar.getInstance().getTimeInMillis();
Intent myAlarm = new Intent(context.getApplicationContext(), AlarmReceiver.class);
PendingIntent recurringAlarm = PendingIntent.getBroadcast(context.getApplicationContext(), 0, myAlarm, PendingIntent.FLAG_CANCEL_CURRENT);
AlarmManager alarms = (AlarmManager) context.getApplicationContext().getSystemService(Context.ALARM_SERVICE);
alarms.setRepeating(AlarmManager.RTC_WAKEUP, current_time, INTERVAL_ALARM, recurringAlarm);
}
And in the receiver:
public class AlarmReceiver extends WakefulBroadcastReceiver {
#Override
public void onReceive(Context context, Intent intent) {
Intent myService = new Intent(context, MyService.class);
context.startService(myService);
}
}
In your service, you should stopSeflf() in the end of your treatment.
Don't forget to register your BroadcastReceiver in your Manifest.xml file
NB: WakefulBroadcastReceiver is deprecated in API level 26.1.0. JobSchedulerService does the work
I'm developing an app that synchronize your local date with the cloud. So I need to check automatically, each 10 minutes, my local data to get the new camera files to upload to the cloud.
So I have used an IntentService that works only when the app is running in foreground. If I close it, my service doesn't upload anything.And I WANT MY INTENTSERVICE WORKS IN BACKGROUND with the AlarmManager.
My IntentService is declared in Manifest.xml:
<!-- Uploader and Deleter Files Service -->
<service android:name=".receiver.UploadDeleteService" android:exported="false" />
<receiver
android:name=".receiver.AlarmReceiver"
android:process=":remote" >
</receiver>
My AlarmReceiver:
public class AlarmReceiver extends BroadcastReceiver {
public static final int REQUEST_CODE = 12345;
public static final String ACTION = "com.codepath.example.servicesdemo.alarm";
// Triggered by the Alarm periodically (starts the service to run task)
#Override
public void onReceive(Context context, Intent intent) {
Intent i = new Intent(context, UploadDeleteService.class);
context.startService(i);
}
}
My ServiceInteractor where I instance my AlarmReceiver inside AlarmManager:
public class ServiceInteractorImpl implements ServiceInteractor {
private Context context;
public ServiceInteractorImpl(Context context){
this.context = context;
}
#Override
public void launchService() {
// Construct an intent that will execute the AlarmReceiver
Intent intent = new Intent(context, AlarmReceiver.class);
// Create a PendingIntent to be triggered when the alarm goes off
final PendingIntent pIntent = PendingIntent.getBroadcast(context, AlarmReceiver.REQUEST_CODE,
intent, PendingIntent.FLAG_UPDATE_CURRENT);
// Setup periodic alarm every 5 seconds
long firstMillis = System.currentTimeMillis(); // alarm is set right away
AlarmManager alarm = (AlarmManager) context.getSystemService(Context.ALARM_SERVICE);
// First parameter is the type: ELAPSED_REALTIME, ELAPSED_REALTIME_WAKEUP, RTC_WAKEUP
// Interval can be INTERVAL_FIFTEEN_MINUTES, INTERVAL_HALF_HOUR, INTERVAL_HOUR, INTERVAL_DAY
Calendar cal = Calendar.getInstance();
cal.add(Calendar.MINUTE, 10);
alarm.setInexactRepeating(AlarmManager.RTC_WAKEUP, firstMillis,
cal.getTimeInMillis(), pIntent);
}
}
My UploadDeleteService where I call to the retrofit implementation module:
public class UploadDeleteService extends IntentService implements ApiConnector.GetObjectListener {
private RemoteInteractor remoteInteractor;
public UploadDeleteService(String name) {
super(name);
}
public UploadDeleteService() {
super("UpdateDeleteService");
}
#Override
protected void onHandleIntent(Intent intent) {
Log.i("SERVICE", "Service running");
remoteInteractor = new RemoteInteractorImpl(getApplicationContext());
remoteInteractor.checkNews(this);
}
#Override
public void onImageUploaded(String type, JSONObject response) {
Log.d("SERVICE", " onImageUploaded ");
//REST OF THE STUFF....
}
}
Please I need a helping hand to solve that problem. I need it works each 10 minutes although the app is closed. Thanks!
For stopped Service:
change "cal.getTimeInMillis()" to "10*60*1000"
cal.add(Calendar.MINUTE, 10); //this will add 10 minute to current time
For Stopped open app when service start:
normally it will not open your app, you need to check what happened in RemoteInteractorImpl.class
you create new instance at onHandleIntent
remoteInteractor = new RemoteInteractorImpl(getApplicationContext());
remoteInteractor.checkNews(this);
I want my app to show a notification with a "GOOD MORNING" message at 6 A.M everyday. As I read, for this I need the app to run in background so I need to use Service.
I have tried the following code but I'm stuck.
MainActivity.java
public void onClickStartService(View v)
{
startService(new Intent(this,MyService.class));
}
public void onClickStopService(View v)
{
stopService(new Intent(this,MyService.class));
}
and MyService.java is
public class MyService extends Service{
private static final String TAG = "MyService";
#Override
public IBinder onBind(Intent arg0) {
// TODO Auto-generated method stub
return null;
}
#Override
public void onCreate() {
Toast.makeText(this, "Congrats! MyService Created", Toast.LENGTH_LONG).show();
Log.d(TAG, "onCreate");
}
#Override
public void onStart(Intent intent, int startId) {
Toast.makeText(this, "My Service Started", Toast.LENGTH_LONG).show();
Log.d(TAG, "onStart");
//Note: You can start a new thread and use it for long background processing from here.
}
#Override
public void onDestroy() {
Toast.makeText(this, "MyService Stopped", Toast.LENGTH_LONG).show();
Log.d(TAG, "onDestroy");
}
}
I have buttons to start and stop the Service and it works. Now I want the service to create notification as I have mentioned at the beginning of the post. How can I do this?
To start the service at a specific time, I suggest you create a BroadcastReceiver triggered by an Alarm, which will in turn start your service.
First write a BroadcastReceiver like this :
public class AlarmReceiver extends BroadcastReceiver {
#Override
public void onReceive(final Context context, final Intent intent) {
context.startService(new Intent(context, MyService.class));
}
/**
* Schedule the next update
*
* #param context
* the current application context
*/
private static void scheduleServiceUpdates(final Context context) {
// create intent for our alarm receiver (or update it if it exists)
final Intent intent = new Intent(context, AlarmReceiver.class);
final PendingIntent pending = PendingIntent.getBroadcast(context, 0, intent, PendingIntent.FLAG_UPDATE_CURRENT);
// compute first call time 1 minute from now
Calendar calendar = Calendar.getInstance();
calendar.add(Calendar.MINUTE, 10);
long trigger = calendar.getTimeInMillis();
// set delay between each call : 24 Hours
long delay = 24 * 60 * 60 * 1000;
// Set alarm
AlarmManager alarmManager = (AlarmManager) context.getSystemService(Context.ALARM_SERVICE);
alarmManager.setRepeating(AlarmManager.RTC, trigger, delay, pending);
// you can use RTC_WAKEUP instead of RTC to wake up the device
}
}
Then you just need to call the scheduleServiceUpdate method to start the reccuring event. If you only use the RTC type, then if the phone is locked when the alarm should trigger the service, it won't and will wait until the device is unlocked by the user. If you use RTC_Wakeup, the service will start exactly at the time given.
Note that there are other methods in the AlarmManager to trigger events.
You can start from PendingIntent and AlarmManager
Tutorial here
Dont forget to add possibility to cancel alarm manager with
mAlarmManager.cancel(pendingIntent);
Also you may want to intercept android.intent.action.BOOT_COMPLETED event to make you app starting immediately after reboot if you want to start your service by schedule.
I'm trying to make a Service, wake up and call itself again after one minute (in this example, I know its bad for battery).
Here is part of the code:
public class SpeechService extends Service {
#Override
public void onCreate() {
super.onCreate();
setUpNextAlarm();
}
public void setUpNextAlarm(){
Intent intent = new Intent(SpeechService.this, this.getClass());
PendingIntent pendingIntent = PendingIntent.getService(this, 0, intent, 0);
long currentTimeMillis = System.currentTimeMillis();
long nextUpdateTimeMillis = currentTimeMillis + 1 * DateUtils.MINUTE_IN_MILLIS;
// Schedule the alarm!
AlarmManager am = (AlarmManager)ContextManager.getApplicationContext().getSystemService(Context.ALARM_SERVICE);
am.set(AlarmManager.RTC_WAKEUP,nextUpdateTimeMillis, pendingIntent);
Log.e("test","I am back!");
}
protected void onHandleIntent(Intent intent)
{
Log.e("test","I am back!");
setUpNextAlarm();
}
}
As you can see I'm calling setUpNextAlarm on service create, I see the log at the end, but then the service is never being called again. I have tried this in an IndentService, it works but I need it to work in a normal Service :(.
Thank you
Use
PendingIntent.getService
not
PendingIntent.getBroadcast
You are getting a Broadcast Intent.
I just ended up using a Service and an IntentService. The IntentService was using the AlarmManager and then it was calling the Service.