I am new to Android, I want to know the most efficient way to perform a background operation which is a simple POST request with JSON Body which will be hit after a fixed interval. Which is best way, Intent Service Or Async Task.
Create a JobScheduler as below
public static void scheduleJob(Context context) {
ComponentName serviceComponent = new ComponentName(context, TestJobService.class);
JobInfo.Builder builder = new JobInfo.Builder(0, serviceComponent);
builder.setMinimumLatency(1 * 1000); // wait at least
builder.setOverrideDeadline(3 * 1000); // maximum delay
charging or not
JobScheduler jobScheduler = context.getSystemService(JobScheduler.class);
jobScheduler.schedule(builder.build());
}
Create the following receiver
public class MyStartServiceReceiver extends BroadcastReceiver {
#Override
public void onReceive(Context context, Intent intent) {
Util.scheduleJob(context);
}
}
Register the receiver in the Android manifest for the BOOT_COMPLETED event.
<receiver android:name="MyStartServiceReceiver" >
<intent-filter>
<action android:name="android.intent.action.BOOT_COMPLETED" />
</intent-filter>
</receiver>
Create a JobService and add your code in to onStartJob
public class TestJobService extends JobService {
private static final String TAG = "SyncService";
#Override
public boolean onStartJob(JobParameters params) {
Intent service = new Intent(getApplicationContext(), LocalWordService.class);
getApplicationContext().startService(service);
Util.scheduleJob(getApplicationContext()); // reschedule the job
return true;
}
#Override
public boolean onStopJob(JobParameters params) {
return true;
}
}
For more details refer : linkhere
Please refer this link: https://developer.android.com/reference/java/util/concurrent/ScheduledExecutorService
Please check my custom class example below. This will execute every 2 seconds.
class CustomThreadExecutor {
private lateinit var scheduledExecutorService: ScheduledExecutorService
private lateinit var scheduledFuture: ScheduledFuture<*>
init {
//Start Scheduler as required
startScheduler()
}
fun startScheduler() {
scheduledExecutorService = Executors.newScheduledThreadPool(2)
scheduledFuture = scheduledExecutorService.scheduleAtFixedRate(
{ tempImageFetch() }, 0, 2, TimeUnit.SECONDS)
}
fun shutdownScheduler() {
//Stop before exit the app or when necessary
scheduledExecutorService.shutdownNow()
}
private fun tempImageFetch() {
//TODO call API
}
}
You can use FirebaseJobDispatcher for API level below and above Lollipop. Here is the github link:
https://github.com/firebase/firebase-jobdispatcher-android
How to implement:
Add the following to your build.gradle's dependencies section:
implementation 'com.firebase:firebase-jobdispatcher:0.8.5'
Make a class for your job service:
public class MyJobService extends JobService {
#Override
public boolean onStartJob(JobParameters job) {
// Do some work here
return false; // Answers the question: "Is there still work going on?"
}
#Override
public boolean onStopJob(JobParameters job) {
return false; // Answers the question: "Should this job be retried?"
}
}
Add this on Manifest:
<service
android:exported="false"
android:name=".MyJobService">
<intent-filter>
<action android:name="com.firebase.jobdispatcher.ACTION_EXECUTE"/>
</intent-filter>
</service>
Add this on your main activity onCreate method:
FirebaseJobDispatcher dispatcher = new FirebaseJobDispatcher(new GooglePlayDriver(context));
Bundle myExtrasBundle = new Bundle();
myExtrasBundle.putString("some_key", "some_value");
Job myJob = dispatcher.newJobBuilder()
// the JobService that will be called
.setService(MyJobService.class)
// uniquely identifies the job
.setTag("my-unique-tag")
// one-off job
.setRecurring(false)
// don't persist past a device reboot
.setLifetime(Lifetime.UNTIL_NEXT_BOOT)
// start between 0 and 60 seconds from now
.setTrigger(Trigger.executionWindow(0, 60))
// don't overwrite an existing job with the same tag
.setReplaceCurrent(false)
// retry with exponential backoff
.setRetryStrategy(RetryStrategy.DEFAULT_EXPONENTIAL)
// constraints that need to be satisfied for the job to run
.setConstraints(
// only run on an unmetered network
Constraint.ON_UNMETERED_NETWORK,
// only run when the device is charging
Constraint.DEVICE_CHARGING
)
.setExtras(myExtrasBundle)
.build();
dispatcher.mustSchedule(myJob);
If your application is for API level Lollipop and above, then you should use JobScheduler or WorkManager
For workmanager:
https://codelabs.developers.google.com/codelabs/android-workmanager/
For JobScheduler:
http://www.vogella.com/tutorials/AndroidTaskScheduling/article.html
Related
I have an Android app I need to call a web service in the background every one minute and depending on web service response send a notification to the user if there is a ticket is opened for him. What is the best way to do this? please note that target SDK is 26
The new JobService must be registered in the Android manifest with the BIND_JOB_SERVICE
permission.
<service
android:name=".TestJobService"
android:label="Word service"
android:permission="android.permission.BIND_JOB_SERVICE" >
</service>
Create the following utility class.
public class Util {
// schedule the start of the service every 10 - 30 seconds
public static void scheduleJob(Context context) {
ComponentName serviceComponent = new ComponentName(context,
TestJobService.class);
JobInfo.Builder builder = new JobInfo.Builder(0, serviceComponent);
builder.setMinimumLatency(1 * 1000); // wait at least
builder.setOverrideDeadline(3 * 1000); // maximum delay
//builder.setRequiredNetworkType(JobInfo.NETWORK_TYPE_UNMETERED); // require unmetered network
//builder.setRequiresDeviceIdle(true); // device should be idle
//builder.setRequiresCharging(false); // we don't care if the device is charging or not
JobScheduler jobScheduler = context.getSystemService(JobScheduler.class);
jobScheduler.schedule(builder.build());
}
}
Create the following receiver
public class MyStartServiceReceiver extends BroadcastReceiver {
#Override
public void onReceive(Context context, Intent intent) {
Util.scheduleJob(context);
}
}
Register the receiver in the Android manifest for the BOOT_COMPLETED event.
<receiver android:name="MyStartServiceReceiver" >
<intent-filter>
<action android:name="android.intent.action.BOOT_COMPLETED" />
</intent-filter>
Create your job
/**
* JobService to be scheduled by the JobScheduler.
* start another service
*/
public class TestJobService extends JobService {
private static final String TAG = "SyncService";
#Override
public boolean onStartJob(JobParameters params) {
Intent service = new Intent(getApplicationContext(), LocalWordService.class);
getApplicationContext().startService(service);
Util.scheduleJob(getApplicationContext()); // reschedule the job
return true;
}
#Override
public boolean onStopJob(JobParameters params) {
return true;
}
}
refer this link
https://www.vogella.com/tutorials/AndroidTaskScheduling/article.html
I'm working on an android app which requires a background task to be performed every hour(Job Scheduler or Service). Task gets executed when the app is running but as soon as I kill the app from foreground, service not work. Is there another way to achieve this?
1. Service
public class NotificationService extends JobService {
private void PrintLog()
{
Log.d("DGVCL", "PrintLog()");
}
#Override
public boolean onStartJob(JobParameters jobParameters) {
Log.d("DGVCL", "onStartJob()");
PrintLog();
jobFinished(jobParameters, false);
return true;
}
#Override
public boolean onStopJob(JobParameters jobParameters) {
Log.d("DGVCL", "onStopJob()");
return true;
}
}
2. Main Activity
JobScheduler jobScheduler = (JobScheduler)getApplicationContext().getSystemService(JOB_SCHEDULER_SERVICE);
ComponentName componentName = new ComponentName(this, NotificationService.class);
JobInfo jobInfo = new JobInfo.Builder(1, componentName)
.setPeriodic(Global.NOTIFICATION_TIME_PERIOD)
.setBackoffCriteria(Global.NOTIFICATION_TIME_PERIOD, JobInfo.BACKOFF_POLICY_LINEAR)
.setPersisted(true).build();
jobScheduler.schedule(jobInfo);
3. manifest
<service android:name="com.hopesndreams.hiren.hd.service.NotificationService" android:permission="android.permission.BIND_JOB_SERVICE" >
</service>
Use WorkManager it is build on top of JobScheduler and it is specifically build to take on all background services both foreground and background functionalities. https://developer.android.com/topic/libraries/architecture/workmanager
* Using AlarmManager*
Step 1:Create a Service
Do your Logic here in the service
public class AService extends Service {
#Override
public int onStartCommand(Intent intent, int flags, int startId) {
//do something
}
#Override
public void onCreate() {
//do somrthing
}
}
Step 2: Create a BroadCast receiver
Start your service with this.
public class AReceiver extends BroadcastReceiver {
#Override
public void onReceive(Context context, Intent intent) {
try {
Intent intent = new Intent(context, AService.class);
context.startService(intent);
} catch (Exception e) {
}
}
}
in MainActivity
Intent liveIntent = new Intent(getApplicationContext(), AReceiver.class);
PendingIntent recurring = PendingIntent.getBroadcast(getApplicationContext(), 0, liveIntent, PendingIntent.FLAG_CANCEL_CURRENT);
AlarmManager alarmManager = (AlarmManager) getSystemService(Context.ALARM_SERVICE);
Calendar updateTime = Calendar.getInstance();
alarmManager.setRepeating(AlarmManager.RTC_WAKEUP, updateTime.getTimeInMillis(), 16 * 60 * 1000, recurring);
//wakeup and starts service in every 16 minutes.
This is the method working for me. Works fine even if you close the app. Works in Xiaomi devices.
Don't forget to add the service inside the manifest
Indeed, WorkManager is the way to go.
You can read up more on other work primitives to suit your task here, but the below implementation uses Worker for threading in WorkManager, which performs work synchronously on a background thread.
public class BackgroundWorker extends Worker {
public BackgroundWorker
(#NonNull Context context,
#NonNull WorkerParameters params) {
super(context, params);
}
#NonNull
#Override
public Worker.Result doWork() {
yourBackgroundTask(); // yourBackgroundTask() implementation
return Result.success();
}
public static void schedulePeriodicWork(Data data) {
// When multiple constraints are specified like below,
// your task will run only when all the constraints are met.
Constraints constraints = new Constraints.Builder()
.setRequiredNetworkType(NetworkType.CONNECTED)
.setRequiresBatteryNotLow(true)
.setRequiresCharging(true)
.build();
PeriodicWorkRequest taskWork = new PeriodicWorkRequest.Builder(BackgroundWorker.class, 60,
TimeUnit.MINUTES)
.setConstraints(constraints)
.setInputData(data)
.build();
WorkManager.getInstance().enqueue(taskWork);
}
}
Later in your MainActivity file, inside onCreate():
Data data = workData();
BackgroundWorker.schedulePeriodicWork(data);
Then outside the onCreate() method,
private Data workData() {
return new Data.Builder() // to build Data objects
.build();
}
One small thing to note, is that though we set the above task to execute every 60 minutes, each iteration may not be executed at the same time interval.
According to Android documentation, WorkManager is meant for deferrable work, and some drift must be tolerated. However, you can check your log console for the update, "WM-WorkerWrapper: Worker result SUCCESS for Work".
Hope this is helpful.
I want to trigger an event when clock ticks 9:00 AM
and again I want trigger another event when clock ticks 4:30 PM, this should be done daily, when user enables it(like using toggle button to enable/disable this feature).
You should refer to this
But, if you have a repetitive task in your Android app, you need to consider that activities and services can be terminated by the Android system to free up resources. Therefore you can not rely on standard Java schedule like the TimerTasks (AlarmManager) class.
<service
android:name=".MyService"
android:label="some_name"
android:permission="android.permission.BIND_JOB_SERVICE" >
</service>
<receiver android:name="MyStartServiceReceiver" >
<intent-filter>
<action android:name="android.intent.action.BOOT_COMPLETED" />
</intent-filter>
</receiver>
This should be in your java class:
public static void scheduleJob(Context context) {
ComponentName serviceComponent = new ComponentName(context, TestJobService.class);
JobInfo.Builder builder = new JobInfo.Builder(0, serviceComponent);
builder.setMinimumLatency(1 * 1000); // wait at least
builder.setOverrideDeadline(3 * 1000); // maximum delay
//builder.setRequiredNetworkType(JobInfo.NETWORK_TYPE_UNMETERED); // require unmetered network
//builder.setRequiresDeviceIdle(true); // device should be idle
//builder.setRequiresCharging(false); // we don't care if the device is charging or not
JobScheduler jobScheduler = context.getSystemService(JobScheduler.class);
jobScheduler.schedule(builder.build());
}
Create another class to Start the Service and Listen :
public class MyStartServiceReceiver extends BroadcastReceiver {
#Override
public void onReceive(Context context, Intent intent) {
Util.scheduleJob(context);
}
}
This is what will tell the service to start and the Parameters.
public class TestJobService extends JobService {
private static final String TAG = "SyncService";
#Override
public boolean onStartJob(JobParameters params) {
Intent service = new Intent(getApplicationContext(), LocalWordService.class);
getApplicationContext().startService(service);
Util.scheduleJob(getApplicationContext()); // reschedule the job
return true;
}
#Override
public boolean onStopJob(JobParameters params) {
return true;
}
}
i want to create something like a reminder app which notify user at given times
, i want to use job scheduler api to achieve this let's say i want to run the service at 9 am and 12 am what should be added in the following code to achieve this.
public void startJobService(){
GooglePlayDriver driver = new GooglePlayDriver(this);
FirebaseJobDispatcher dispatcher = new FirebaseJobDispatcher(driver);
Bundle myExtrasBundle = new Bundle();
myExtrasBundle.putString("some_key", "some_value");
Job myJob = dispatcher.newJobBuilder()
.setService(jobservice.class)
.setTag("unique-tag")
.setExtras(myExtrasBundle)
.build();
dispatcher.mustSchedule(myJob);
}
//this is the JobService class
public class jobservice extends JobService{
private static final String TAG = "jobservice";
#Override
public boolean onStartJob(JobParameters job) {
Log.d(TAG, "onStartJob: "+job.getExtras());
return true;
}
#Override
public boolean onStopJob(JobParameters job) {
return false;
}
}
Unfortunately it seems that the JobService does not provide this api. Two things you can do:
Use Alarm Manager to trigger the job service when you want or
Run you job service frequent (let's say once per hour). Then check if the current time is on your desired interval. If yes proceed, if no abort the job.
For example:
final Job job = dispatcher.newJobBuilder()
.setService(MyService.class)
.setTag(MyService.class.getName())
.setRecurring(true)
.setLifetime(Lifetime.FOREVER)
.setTrigger(Trigger.executionWindow(HOUR, 2 * HOUR))
.setReplaceCurrent(false)
.setRetryStrategy(RetryStrategy.DEFAULT_EXPONENTIAL)
.build();
And then inside your Job Service:
#Override
public boolean onStartJob(JobParameters job) {
if (!nowIsInDesiredInterval()) {
Timber.i("Now is not inside the desired interval. Aborting.");
return false;
}
// else execute your job
// .....
return false;
}
I am trying to execute a periodic task by using job scheduler . I want to call a service after each 10 second, it work fine for couple of hour but after sometimes it stops working and it doesn't work after device restart .
Here is what I have tried
ComponentName getAlertJobComponent = new ComponentName(context.getPackageName(), GetAlertJobService.class.getName());
JobInfo.Builder getAlertbuilder = new JobInfo.Builder(Constants.getAlertJobid, getAlertJobComponent);
getAlertbuilder.setRequiredNetworkType(JobInfo.NETWORK_TYPE_ANY); // require unmetered network
getAlertbuilder.setRequiresDeviceIdle(true); // device should be idle
getAlertbuilder.setPeriodic(10 * 1000);
getAlertbuilder.setRequiresCharging(false); // we don't care if the device is charging or not
JobScheduler getAlertjobScheduler = (JobScheduler) context.getSystemService(Context.JOB_SCHEDULER_SERVICE);
getAlertjobScheduler.schedule(getAlertbuilder.build());
And my job sevice is
public class GetAlertJobService extends JobService {
#Override
public boolean onStartJob(JobParameters params) {
if (!Utility.isServiceRunning(GetAlertService.class, getApplicationContext())) {
startService(new Intent(getApplicationContext(), GetAlertService.class));
}
jobFinished(params, false);
return true;
}
#Override
public boolean onStopJob(JobParameters params) {
return true;
}
}
Here GetAlertService is service that is calling a web service
EDIT
I also added this on Boot receiver like following
public class Boot extends BroadcastReceiver {
#Override
public void onReceive(Context context, Intent intent) {
if (android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.LOLLIPOP) {
ComponentName getAlertJobComponent = new ComponentName(context.getPackageName(), GetAlertJobService.class.getName());
JobInfo.Builder getAlertbuilder = new JobInfo.Builder(Constants.getAlertJobid, getAlertJobComponent);
getAlertbuilder.setRequiredNetworkType(JobInfo.NETWORK_TYPE_ANY); // require unmetered network
getAlertbuilder.setRequiresDeviceIdle(true); // device should be idle
getAlertbuilder.setPeriodic(10 * 1000);
getAlertbuilder.setPersisted(true);
getAlertbuilder.setRequiresCharging(false); // we don't care if the device is charging or not
JobScheduler getAlertjobScheduler = (JobScheduler) context.getSystemService(Context.JOB_SCHEDULER_SERVICE);
getAlertjobScheduler.schedule(getAlertbuilder.build());
}
}
}
in manifest
<receiver
android:name=".broadcastreceiver.Boot"
android:enabled="true">
<intent-filter android:priority="999">
<action android:name="android.intent.action.BOOT_COMPLETED" />
</intent-filter>
</receiver>
The reset issue is solved by adding setPersisted(true) on the job builder. For the stops working after a long time- is the device asleep? If so, its likely a doze issue.