I want to call a method once every day to spawn the zombies in my app.
The following method should create a JobScheduler that does this.
My question is: Do I call this method once or can I call it everytime at the startup of the app?
public static void startZombieSpawnService(Context context) {
JobScheduler jobScheduler = (JobScheduler) context.getSystemService(context.JOB_SCHEDULER_SERVICE);
long intervaloDeRepeticao = TimeUnit.DAYS.toMillis(1);
jobScheduler.schedule(new JobInfo.Builder(1, new ComponentName(context, ZombieSpawnService.class)).setPeriodic(intervaloDeRepeticao).setp.build());
}
If you hold the RECEIVE_BOOT_COMPLETED permission, then you can also use setPersisted(true) from JobInfo.Builder(). Then you only need to call it once and it will persist across reboots too.
Otherwise, when your app starts, you can check if your job is scheduled using this function:
public static boolean isJobScheduled(Context mContext, int jobID) {
JobScheduler mScheduler = (JobScheduler)
mContext.getSystemService(Context.JOB_SCHEDULER_SERVICE);
for (JobInfo jobInfo : mScheduler.getAllPendingJobs()) {
if (jobID == jobInfo.getId()) {
return true;
}
}
return false;
}
If it is not scheduled, then schedule it.
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'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 came to know that background services are not a way around in order to perform background task instead Job Scheduler was focused more as an alternative
i was applying the job scheduler functionality in my app and i was so confused that why my job is not running as expected whereas in android emulator it is running smoothly
below is my code which i have applied so far
Java.Lang.Class javaClass = Java.Lang.Class.FromType(typeof(jobsched));
ComponentName component = new ComponentName(this, javaClass)
JobInfo.Builder builder = new JobInfo.Builder(999, component)
.SetMinimumLatency(1000) // Wait at least 1 second
.SetOverrideDeadline(5000) // But no longer than 5 seconds
.SetPersisted(true)
.SetRequiredNetworkType(NetworkType.Any);
JobInfo jobInfo = builder.Build();
JobScheduler jobScheduler = (JobScheduler)GetSystemService(JobSchedulerService);
int result = jobScheduler.Schedule(jobInfo);
if (result == JobScheduler.ResultSuccess)
{
// The job was scheduled.
}
else
{
// Couldn't schedule the job.
}
And Scheduler service
public override bool OnStartJob(JobParameters #params)
{
Task.Run(() =>
{ });
JobFinished(#params, true);
return true;
}
public override bool OnStopJob(JobParameters #params) {
return true;
}
above scheduler seems to work fine when the app is open but when the app is closed by swiping away from recent task it doesn't notify me any more
i am missing something, please help me with this
Scenario
Hi,
I have a JobService that I launch when I come to my HomeScreen. This job service takes my requests out from my DB and execute them whenever internet is available. So even if the device is offline, I insert my transactions in my DB and whenver internet comes, my JobService executes those transactions.
Problem
The Problem is that I come to my HomeScreen from a number of screens. So everytime I come to HomeScreen, I starts my JobService again. So if I came to my HomeScreen three time before internet comes, now three different services are running for same task. So I wanted to check if the service is already running, I won't start one.
What I have Tried
The Code of starting my JobService is very simple. I wrote a method to start it and call it in OnCreate()
public JobScheduler initQueue(Context context){
if(jobScheduler==null){
jobScheduler = (JobScheduler)context.getSystemService(JOB_SCHEDULER_SERVICE);
}
return jobScheduler;
}
public void executeQueue(){
initQueue(this);
ComponentName jobService = new ComponentName(this.getPackageName(), OfflineQueueService.class.getName());
JobInfo jobInfo = new JobInfo.Builder(2,jobService).
setPersisted(true).
setRequiredNetworkType(JobInfo.NETWORK_TYPE_ANY).
build();
jobScheduler.schedule(jobInfo);
}
I call executeQueue in onCreate().
I searched on StackOverflow and found this link:
How to check JobService is running or not in android?.
So I now have this method in my HomeScreen to check if my JoService is running:
public static boolean isJobServiceOn( Context context ) {
JobScheduler scheduler = (JobScheduler) context.getSystemService( Context.JOB_SCHEDULER_SERVICE ) ;
boolean hasBeenScheduled = false ;
List<JobInfo> list =scheduler.getAllPendingJobs();
for ( JobInfo jobInfo : scheduler.getAllPendingJobs() ) {
if (jobInfo.getId() == 2 ) {
hasBeenScheduled = true ;
break ;
}
}
return hasBeenScheduled ;
}
But in this method, It never lists my JobService running and I get false everytime, Hence again running into my same problem of multiple instances of the JobService.
I hope I made my question clear.
Hi did a sample of JobScheduler in my app.
This is how I initiate it
jobScheduler = (JobScheduler) getSystemService(JOB_SCHEDULER_SERVICE);
ComponentName jobService = new ComponentName(getPackageName(),
MyJobService.class.getName());
JobInfo jobInfo = new JobInfo.Builder(MYJOBID, jobService)
.setRequiredNetworkType(JobInfo.NETWORK_TYPE_ANY)
.setExtras(bundle).build();
jobScheduler.schedule(jobInfo);
And I showed a toast in the JobService:
#RequiresApi(api = Build.VERSION_CODES.LOLLIPOP)
public class MyJobService extends JobService {
public MyJobService() {
}
#Override
public boolean onStartJob(JobParameters params) {
// UtilityMethods.showToast(this,params.getExtras().getString("json"));
Toast.makeText(this,"test",Toast.LENGTH_SHORT).show();
return false;
}
#Override
public boolean onStopJob(JobParameters params) {
UtilityMethods.showToast(this,"onStop()");
return false;
}
}
And this was working perfectly fine even I tried turning off the internet and killing app from background.
I then tried building a similar thing in one of my libraries. I wrote the same code in the library and I am calling it from my app's MainActivity. But this time, When I kill app from background, it stops working. Can anyone tell me why?
My MainActivity where I initialize it
JobScheduler jobScheduler = (JobScheduler) getSystemService(JOB_SCHEDULER_SERVICE);
ComponentName jobService = new ComponentName(getPackageName(),
MyJobService.class.getName());
JobInfo jobInfo = new JobInfo.Builder(MYJOBID, jobService)
.setRequiredNetworkType(JobInfo.NETWORK_TYPE_ANY).build();
jobScheduler.schedule(jobInfo);
It is working when I start it from onCreate and not working if I start it from a callback funtion().
Any help is really appreciated.
Android> 7 automatically saves battery power. You must enable the app's battery saver stop
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
Intent intent = new Intent();
String packageName = getPackageName();
PowerManager pm = (PowerManager) getSystemService(POWER_SERVICE);
if (!pm.isIgnoringBatteryOptimizations(packageName)) {
intent.setAction(Settings.ACTION_REQUEST_IGNORE_BATTERY_OPTIMIZATIONS);
intent.setData(Uri.parse("package:" + packageName));
startActivity(intent);
}
}
add this to AndroidManifest.xml
<uses-permission android:name="android.permission.REQUEST_IGNORE_BATTERY_OPTIMIZATIONS"/>
Make this return true
#Override
public boolean onStartJob(JobParameters params) {
// UtilityMethods.showToast(this,params.getExtras().getString("json"));
Toast.makeText(this,"test",Toast.LENGTH_SHORT).show();
return true;
}
and start a new thread from here(as this is executed on mainthread only).
onStartJob
added in API level 21
boolean onStartJob (JobParameters params)
Override this method with the callback logic for your job. Any such logic needs to be performed on a separate thread, as this function is executed on your application's main thread.
Parameters
params JobParameters: Parameters specifying info about this job, including the extras bundle you optionally provided at job-creation time.
Returns
boolean True if your service needs to process the work (on a separate thread). False if there's no more work to be done for this job.