Migrating from IntentService to JobIntentService for Android O - android

Previously I was using IntentService to send data to the server periodically. However, since Android O limiting background task and processes I am moving towards JobIntentService.
My Activity code to schedule an alarm
Intent intent = new Intent(BaseActivity.this, EventBroadcastReceiver.class);
// Create a PendingIntent to be triggered when the alarm goes off
final PendingIntent pIntent = PendingIntent.getBroadcast(this, EventBroadcastReceiver.REQUEST_CODE,
intent, PendingIntent.FLAG_UPDATE_CURRENT);
// Setup periodic alarm every half hour
long firstMillis = System.currentTimeMillis(); // alarm is set right away
AlarmManager alarm = (AlarmManager) this.getSystemService(Context.ALARM_SERVICE);
alarm.setInexactRepeating(AlarmManager.RTC_WAKEUP, firstMillis,
AlarmManager.INTERVAL_HALF_HOUR, pIntent);
And my Service is as follows
public class EventAnalyticsService extends JobIntentService {
#Override
protected void onHandleWork(#NonNull Intent intent) {
// Perform your task
}
#Override
public void onCreate() {
super.onCreate();
}
}
Receiver for this code is
public class EventBroadcastReceiver extends BroadcastReceiver {
public static final int REQUEST_CODE = 12345;
#Override
public void onReceive(Context context, Intent intent) {
Intent myIntent = new Intent(context, EventAnalyticsService.class);
context.startService(myIntent);
}
}
However this is not working for Android O when app is in background and if I use context.startForegroundService(myIntent); to start my service it is throwing exception as Context.startForegroundService() did not then call Service.startForeground()

JobIntentService is there mostly for a service that will be invoked from the UI, such as a service to perform a large download, initiated by the user clicking a "Download!" button.
For periodic background work, use JobScheduler and a JobService. If you need to support older than Android 5.0, use a suitable wrapper library (e.g., Evernote's android-job), one that will use JobScheduler on newer devices and AlarmManager on older devices.
Alternatively, stick with AlarmManager, but use a foreground service.

Related

Run a JobService Constantly in Android-Even App is killed

I am just newbie to android,please help a little. i am trying to use JobService or com.firebase.jobdispatcher.JobService in my android application but as far as i studied i see that the JOB SERVICE runs on Main Thread and as long as application is running either in background or forground it keep doing its schedule work.
But the issue is i want to do Get users location lets say after every 30 minutes even if the application is removed from application tray. i am confused in following points
If i run a sticky service it does not give me scheduling
If i use Job Service it gives scheduling but terminates as application is
closed.
Is there any way to run a service which run even after application is killed and do schedule tasks as well?
you can use AlarmManager link
Create Your Server class :
public class MService extends IntentService {
public MyTestService() {
super("MService");
}
#Override
protected void onHandleIntent(Intent intent) {
// Your firebase task
}
}
then your broadcast
public class MReceiver extends BroadcastReceiver {
#Override
public void onReceive(Context context, Intent intent) {
Intent in = new Intent(context, MService.class);
context.startService(in);
}
}
finally
Intent intent = new Intent(getApplicationContext(), MReceiver.class);
final PendingIntent pIntent = PendingIntent.getBroadcast(this, MReceiver.REQUEST_CODE,intent, PendingIntent.FLAG_UPDATE_CURRENT);
long firstMillis = System.currentTimeMillis();
AlarmManager alarm = (AlarmManager) this.getSystemService(Context.ALARM_SERVICE);
alarm.setInexactRepeating(AlarmManager.RTC_WAKEUP, firstMillis, AlarmManager.INTERVAL_HALF_HOUR, pIntent);

How to keep a service alive using AlarmManager.setInexactRepeating()?

I have some existing code that spawns a service intent which does a bunch of stuff in the background. This code does work...
Intent serviceIntent = new Intent(context, APMService.class);
serviceIntent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
context.startService(serviceIntent);
My question is: how to change this to use the AlarmManager.setInexactRepeating(...) methods?
I have changed the above code to this:
Intent serviceIntent = new Intent(context, APMService.class);
serviceIntent.putExtra("STARTED_BY", starter);
serviceIntent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
//Set up recurring alarm that restarts our service if
// it crashes or if it gets killed by the Android OS
AlarmManager am = (AlarmManager) context.getSystemService(Context.ALARM_SERVICE);
PendingIntent pi = PendingIntent.getService(context, 0, serviceIntent, 0);
//am.cancel(pi);
am.setInexactRepeating(
AlarmManager.ELAPSED_REALTIME_WAKEUP //wake up the phone if it's asleep
, cal.getTimeInMillis()
, 10000
, pi);
And I have added these permissions to AndroidManifest.xml...
<uses-permission android:name="com.android.alarm.permission.SET_ALARM"/>
<uses-permission android:name="com.android.alarm.permission.WAKE_LOCK"/>
My understanding is that this is supposed to start the service immediately and then try to restart it again every 10 seconds. But this code isn't working properly.
Using this new code, the service never starts at all and I cannot see why not. To complicate matters the debugger never seems to attach to the app in time to see what's going on.
Can anyone see what I'm doing wrong?
Put AlarmManager code under onDestroy() function of service to schedule start of service as below:
#Override
public void onDestroy() {
/**
* Flag to restart service if killed.
* This flag specify the time which is ued by
* alarm manager to fire action.
*/
final int TIME_TO_INVOKE = 5 * 1000; // try to re-start service in 5 seconds.
// get alarm manager
AlarmManager alarms = (AlarmManager) context.getSystemService(Context.ALARM_SERVICE);
Intent intent = new Intent(context, AutoStartServiceReceiver.class);
PendingIntent pendingIntent = PendingIntent
.getBroadcast(context, 0, intent, PendingIntent.FLAG_CANCEL_CURRENT);
// set repeating alarm.
alarms.setRepeating(AlarmManager.RTC_WAKEUP, System.currentTimeMillis() +
TIME_TO_INVOKE, TIME_TO_INVOKE, pendingIntent);
}
And handle starting of your service in AutoStartServiceReceiver as below:
public class AutoStartServiceReceiver extends BroadcastReceiver {
private static final String TAG = AutoStartServiceReceiver.class.getSimpleName();
#Override
public void onReceive(Context context, Intent intent) {
// check broadcast action whether action was
// boot completed or it was alarm action.
if (intent.getAction().equals(AppConstants.ACTION_ALARM_INTENT)) {
context.startActivity(new Intent(context, YourActivity.class));
// handle service restart event
LockerServiceHelper.handleServiceRestart(context);
}
}
}
Kindly note that, your service will not restart if you stop it manually from settings-apps-running apps-your app.
Your service is not starting because of AlarmManager.ELAPSED_REALTIME_WAKEUP, while it should be using AlarmManager.RTC_WAKEUP
If you want to run every 10s keep in mind that above API 21 alarm intervals below 60s are rounded up to 60s.
Also, consider using WakefulIntentService
https://github.com/commonsguy/cwac-wakeful

Function of Service in Context of Alarm App (Android)

I am trying to develop an alarm system in android that would function after the application closes, making multiple simultaneous alarms possible (which should be repeatable and cancelable, but I have read documentation for such functions).
Currently, I only have the UI (which fires off intents to receiver at scheduled times through AlarmManager) and the Receiver class (which extends BroadCastReceiver). Although the alarm somehow functions, there have been issues like the alarm not sounding at appropriate times until I open app again and not providing the correct alarm.
I have read that a service is commonly used in such apps to provide functionality of the application when the activity is closed. Thus, I am interested in what a service would provide in the context of the application, and whether my problems are solvable through service.
I have searched answers and read that a service is useful for running background operations (i.e. mp3 or alarm) For example, google states that "Another application component can start a service and it will continue to run in the background even if the user switches to another application. ". The following answer states that to use "alarm simultaneously you must use Service class for that".
Therefore, I think that a service may be useful for providing the functionality for the alarm. However, some people seem to represent a service as a either or with AlarmManager, which I am currently using. Most others seem to use AlarmManger to start service or perform an action of that nature. I would be very grateful if someone could shed light on what a service provides (I've already read google's explanation but it did not clear up whether I need it or not).
Sending intent from UI
if (row.get(7) == 1) {
Intent alarmIntent = new Intent(MainActivity.this, AlarmReceiver.class);
alarmIntent.putExtra("id", (long) row.get(0));
AlarmManager alarmManager = (AlarmManager) getSystemService(Context.ALARM_SERVICE);
long longValue = (long) row.get(0);
int intValue = (int) longValue;
PendingIntent pendingIntent = PendingIntent.getBroadcast(MainActivity.this, intValue, alarmIntent, PendingIntent.FLAG_UPDATE_CURRENT);
if (row.get(8) == 1) {
alarmManager.setRepeating(AlarmManager.RTC_WAKEUP, (long) row.get(6), (long) row.get(9), pendingIntent);
} else {
alarmManager.set(AlarmManager.RTC_WAKEUP, (long) row.get(6), pendingIntent);
}
}
AlarmReceiver class
public class AlarmReceiver extends BroadcastReceiver {
#Override
public void onReceive(Context context, Intent intent)
{
long id = intent.getLongExtra("id", 0);
Notification.Builder builder = new Notification.Builder(context)
.setSmallIcon(R.drawable.ic_action_search)
PendingIntent pi = PendingIntent.getActivity(context, (int)id, new Intent(), 0);
NotificationManager nm = (NotificationManager)
context.getSystemService(Context.NOTIFICATION_SERVICE);
nm.notify((int)id, builder.build());
}
}
Try to use service like this :
public class UpdateService extends Service {
#Override
public int onStartCommand(Intent intent, int flags, int startId)
{
return START_STICKY;
}
}
When onStartCommand returns START_STICKY, system restarts service if it's killed.
Use this link

Android repeating alarm not repeating correctly

I have an alarm that I am wanting to repeat around every 5 minutes. For testing purposes, I have it set to repeat once every 5 seconds instead, as such:
AlarmManager alarmManager = (AlarmManager)getActivity().getSystemService(getActivity().ALARM_SERVICE);
Intent intent = new Intent(getActivity(), CoordinateAlarmReceiver.class);
PendingIntent pendingIntent = PendingIntent.getService(getActivity(), 1, intent, 0);
int repeatSeconds = 5;
alarmManager.setInexactRepeating(AlarmManager.RTC_WAKEUP, System.currentTimeMillis(),
repeatSeconds * 1000, pendingIntent);
And the receiving IntentService prints a log statement when it receives the alarm. However, it fires around once every minute and a half instead of once every 5 seconds, where is it set incorrectly? I have also tried using setRepeating() instead of setInexactRepeating() but I get the same results.
Here is my alarm receiver:
public class CoordinateAlarmReceiver extends IntentService {
public CoordinateAlarmReceiver(){
super("CoordinateAlarmReceiver");
}
/*
Alarm received, get new contacts which then shows notification
*/
#Override
protected void onHandleIntent(Intent intent) {
MyLog.i("coordinate alarm received");
//new GetNewContactsTask(this).execute();
}
}
I assume you are on api 19 or above. The alarmmanager documentations says:
Note: Beginning with API 19 (KITKAT) alarm delivery is inexact: the OS will shift alarms in order to minimize wakeups and battery use. There are new APIs to support applications which need strict delivery guarantees; see setWindow(int, long, long, PendingIntent) and setExact(int, long, PendingIntent). Applications whose targetSdkVersion is earlier than API 19 will continue to see the previous behavior in which all alarms are delivered exactly when requested.
You tried using setRepeating() but on api 19 and above this calls setInexactRepeating(). On 19 and above you
setInexactRepeating(): Schedule a repeating alarm that has inexact trigger time requirements; for example, an alarm that repeats every hour, but not necessarily at the top of every hour.
This explains your weird result.
If you want to set is at a excat time, you should use setExact. Unfortunalety there is no setExactRepating so you have to create this yourself. Schedule a new alarm after one executes or something like that.
Note in the alarmmanager documentation:
Note: The Alarm Manager is intended for cases where you want to have your application code run at a specific time, even if your application is not currently running. For normal timing operations (ticks, timeouts, etc) it is easier and much more efficient to use Handler.
Maybe you should take a look at this.
I had a similar problem in which I needed a Service fired every 15 seconds... I did the following.
I have a class that extends Application called MyApplication. This class holds an instance of an alarm manager.
public class MyApplication extends Application {
private MyAlarmManager alarmMgr;
#Override
public void onCreate() {
Log.d(TAG, "MyApplication onCreate");
super.onCreate();
Log.d(TAG, "initing alarmMgr ...");
alarmMgr = new MyAlarmManager(this);
}
public MyAlarmManager getAlarmManager(){
return alarmMgr;
}
}
An AlarmManager called MyAlarmManager creates, starts & stops the alarms AND NOW sets the next alarm for this one service.
public class MyAlarmManager {
private MyApplication mApp;
private Intent intent;
private PendingIntent pendingIntent;
private AlarmManager alarmMgr;
private static final long FREQUENCY = 15000;
public MyAlarmManager(Context context) {
mApp = (MyApplication) context;
// Android alarm service
alarmMgr = (AlarmManager) context.getSystemService(Context.ALARM_SERVICE);
// service to be fired every 15 seconds
intent = new Intent(context, MyService.class);
pendingIntent = PendingIntent.getService(context, 1, intent, PendingIntent.FLAG_UPDATE_CURRENT);
setNextAlarm();
}
public void setNextAlarm(){
Log.d(TAG, "setting next alarm...");
alarmMgr.set(AlarmManager.RTC_WAKEUP, (System.currentTimeMillis() + FREQUENCY), pendingIntent);
}
private void stopAlarms(){
Log.d(TAG, "stopping Alarms");
alarmMgr.cancel(pendingIntent);
}
}
When the Service is fired I get an instance of MyApplication, get the AlarmManager and schedule the next alarm.
public class MyService extends Service {
MyApplication mApp;
#Override
public int onStartCommand(Intent intent, int flags, int startId) {
Log.d(TAG, "in onStartCommand");
// init the app reference if needed
if (mApp == null) {
Log.d(TAG, "app was null. Creating now...");
mApp = (MyApplication) getApplicationContext();
}
// schedule the next zone check
mApp.getAlarmMgr().setNextAlarm();
// custom functionality ...
}

AlarmManager only lets one Service through when used with setRepeating in Android

I've been struggling with this for a couple of days. What I want to do is run a service periodically, about 2-3 minutes apart. I have an Activity that is responsible for the interface and setting up the first alarm.
The alarm is configured by a BroadcastReceiver which looks like this:
public class Receiver extends BroadcastReceiver {
#Override
public void onReceive(Context context, Intent intent) {
String message = "Alarm worked";
Toast.makeText(context, message, Toast.LENGTH_SHORT).show();
setAlarm(context);
}
public void setAlarm(Context context){
AlarmManager am = (AlarmManager) context.
getSystemService(Context.ALARM_SERVICE);
Intent intent = new Intent(context, Receiver.class);
PendingIntent pi = PendingIntent.getBroadcast(context,
0, intent, PendingIntent.FLAG_UPDATE_CURRENT);
Intent dailyUpdater = new Intent(context, DiscoveryService.class);
context.startService(dailyUpdater);
am.set(AlarmManager.RTC_WAKEUP, System.currentTimeMillis()
+ (1000 * 30) , pi);
}
}
I've tried using setRepeating for AlarmManager, but it still has the same effect. What happens is that the AlarmManager works how it should, it fires an Intent which the receiver gets and executes onReceive periodically, as it should. However, it executes the service only the first time. After the first time, the alarms still go off, but the service is not executed.
I read some threads from people with similar problems, and one of them mentioned that PendingIntent lasts for only one send. Thus, I opted out to setting the alarm every time so I can set pendingIntent flag for updating every time.
I tried making my service an intentService, which is fine, but then my bluetooth scanner inside the service does not work because intentService thread terminates without waiting for my bluetooth discovery to finish.
Anyone have any idea what can help me?
Here is part of my service:
public class DiscoveryService extends Service {
public void onCreate() {
super.onCreate();
Toast.makeText(this, "MyAlarmService.onCreate()",
Toast.LENGTH_LONG).show();
findEverything();
}
}
EDIT: This is the code that I currently have.
public void onReceive(Context context, Intent intent) {
String message = "Alarm worked";
Toast.makeText(context, message, Toast.LENGTH_SHORT).show();
Intent dailyUpdater = new Intent(context, DiscoveryService.class);
context.startService(dailyUpdater);
}
public void setAlarm(Context context){
// get a Calendar object with current time
AlarmManager am=(AlarmManager)context.
getSystemService(Context.ALARM_SERVICE);
Intent intent = new Intent(context, Receiver.class);
PendingIntent pi = PendingIntent.getBroadcast(context, 0, intent,
PendingIntent.FLAG_UPDATE_CURRENT);
am.setRepeating(AlarmManager.RTC_WAKEUP, System.currentTimeMillis(),
(1000 * 30) , pi);
}
What happens is that the AlarmManager works how it should, it fires an Intent which the reciever gets and executes onReceive periodically, as it should. However, it executes the service only the first time. After the first time, the alarms still go off, but the service is not executed.
You are calling startService() once when you are scheduling the alarm. You are not calling startService() at all from your BroadcastReceiver. Yet you are scheduling the alarm via the BroadcastReceiver. Hence, when the alarm goes off, the service will not be sent a command, because you are not sending it a command.
I read some threads from people with similar problems, and one of them mentioned that PendingIntent lasts for only one send.
That is only if you use FLAG_ONE_SHOT.
Anyone have any idea what can help me?
Call startService() from your onReceive() method, instead of from your setAlarm() method. Also, add in all the WakeLock management logic, since you are using a _WAKEUP alarm and you are not able to use my WakefulIntentService.

Categories

Resources