As an infant, the application is unaware of the possibilities and restrictions that the Environment could offer it.Still, the curious application rolls up its sleeves and starts shaping itself to become what it is meant to do.
In this Article, I will be discussing the story that describes the struggle of this application,
the problems it is going to face, how it will figure out the solutions,
how it is going to make the right choice in choosing the appropriate.
The will, and the hope that would make it possible for the immature to achieve its goal…
A “Hello world” Android application has a workflow like in the flowchart below.
The Requirement need is as follows:
The user can schedule one/multiple tasks (Jobs) that run periodically (Every hour, every day, every week).
The user will provide the start time and the periodic frequency.
Also, the user will provide a URL which is the path of a file and an Email address.
The application needs to schedule a task for the start time, as the system time=start time, the application will hit the URL and download the file from the server.
Afterward, the application has to process the data in the file and send the result to the Email ID provided by the user.
Simultaneously, it has to schedule to task again for the given frequency.
start time= start time + frequency
ex- If the start time was 10:00 AM and the frequency is every hour, then
start time = 10:00 AM + 1 hour =11:00 AM
Hence, the next time the complete task will run at 11:00 AM.
Scene 1: Convert the requirement workflow to the technical workflow
The “Hello world” Application has the above requirement in front of it. Deeply analyzing the requirement, MyApp is iterating its knowledge to make a technical workflow of this use case…
“It seems easy, I have to just make a user interface, get these fields from the user and store them somewhere, then I’ll make a thread that will do the rest of the thing.”, MyApp said overviewing the requirement flowchart.
“Let’s make a technical flow diagram for this requirement, I can then visualize things clearly”, it opens the flowchart maker and starts designing the components.
The app checked out the various storage techniques in Android and figured out the SQLite as the best option to store all the data.
“OK!, now I need a thread that will get the data from the database and download the file from the URL”
The app does not want to mess up things, hence It decides to process the file and send the status Email via another thread.
“I need something that will invoke the first thread at the start time and then the threads will do what they are meant for”, MyApp is looking for something that can schedule the task at the start time.
“Oh yes! there are schedules that can do the job of waking up the thread at that time”
“For now let’s complete the flowchart and then I’ll walk up to the Android OS and ask it to guide a scheduler that can do the job for me.”
Also, it has to update the time for the next frequency in the DB and the scheduler to run it again and again periodically. With all this in mind, the app ends up with a technical flowchart that looks something like this:
understanding the flow diagram
According to the flowchart, the user would enter the details in the text fields in the user interface. SQLite will store this data.
simultaneously, schedule a scheduler that will ask the Android OS to start a thread at the start time. At this instance, the system current time will be equal to the start time.
The thread 1 will iterate the Database and check if there is any job that matches the current system time i.e; the start time.
Obviously, it will find the job! Afterward, another thread, Thread 2 will fetch the details of the matched job, hit the URL and download the file at the URL.
Simultaneously, Thread 1 will update the time in the database with the next time according to the frequency and also update the schedule with the next time to wake up the thread 1 at next time.
The Thread 3 process the downloaded file and forwards the report to the Email ID provided by the user.
Scene 2: First meeting with the Android OS
“Hey Android, how are you?” MyApp said smiling towards the OS.
“I am good, working on the release of Android P. You tell what are you up to?” Android said not even looking towards the app.
“I have a requirement to schedule a job for a specific time, can you please help with that?” MyApp says.
Still busy in its chores, OS replied, “I have recently released JobScheduler API, go for it, it will help”.
OS was really busy, so MyApp leaves to meet the JobScheduler to discuss if it can help. MyApp is happy with the name itself. All the way it is thinking that “I have a job and need to schedule it, thanks a lot mighty Android OS you referred me to JobScheduler, it will surely help me.”
Scene 3: meeting with JobScheduler
Fantasizing all this, it approaches JobScheduler.
“Hey JobScheduler, I am MyApp, our OS referred me to you. Can you help me with task scheduling?” MyApp introduced itself to the JobScheduler.
“Of course buddy! I am made for that,” JobScheduler says politely, ” Tell me the scenario”.
MyApp shows both the flow charts to the JobScheduler and simultaneously explains everything to it.
Checking out the flow, JobScheduler smiles and says, “sorry, I cannot help you with that, I do not work this way. ”
“Then how do you work? Can you explain to me, please… I’ll change the flow according to you.” MyApp says excitedly.
JobScheduler asks MyApp to sit and starts explaining its capabilities.
“You give me a task that is to be done when favorable conditions meet, and I assure you, I’ll do the task as soon as the system attains the favorable state.*”
with a clear confident voice, it continues…
“I guarantee to get your job done but I work on basis of conditions, not time.“
MyApp didn’t understand anything, and this is clearly visible on its face.
“Favourable conditions like…?” It asks.
JobScheduler: “suppose you need to do a task when several conditions meet, for an instance, you may say, like other apps I also want to sync the data of my app to the backend server daily. Furthermore, I have additional conditions like, do the sync when the device is charging and also connected to the Internet, in this case, I guarantee, I’ll do the task when these conditions meet. “
MyApp: ” But I also have a similar condition then why are you saying No to me.”
JobScheduler: ” you said you want to do the job at an exact time. “
MyApp: ” but I also have to do the task every hour or day. “
JobScheduler: ” check the flow again brother, you need to start the job at RTC (Real Time Clock) and run every frequency at the specific time. “
” So… What’s the problem with this? “
JobScheduler: ” what if your device is not connected to the Internet at that time or the device is turned off, will I be able to hit the URL at that time ?”
Nodding its head, my app replies in a low tone, ” No…”
JobScheduler: “brother… I guarantee to do a task means it will be done. But only when all the conditions meet. RTC is not my cup of tea! “
for further reference visit the JobScheduler official docs
After hearing all this, MyApp starts thinking about how it changes the flow so that it can come out clean on the conditions of job scheduler.
But there is no other way as every frequency has to be done at a very specific time. So it has to rely on the RTC only and need to figure out something else for its case.
Thinking all this in mind, myApp asks JobScheduler for any other alternative who can do this time task.
JobScheder refers it back to OS for further help.
Scene 4: Second meeting with Android OS
Same as before, Android was busy with its chores.
Hesitatingly, MyApp walks towards and says, “Hello!”
“Hi! is your work done?, Android asks.
“No! JobScheduler refuses to do my work because my use case relies on exact time. It works on conditions or whatever…”, says MyApp.
“Hmmm… Ok, goto Alarm Manager, this task scheduling API works on various time conditions. It will help you with this.”, Android provides the alternate and gets back to its work again.
“I hope so…”, Says MyApp and leaves to meet the Alarm Manager.
Scene 5: Meeting with Alarm Manager
“Hiii…” MyApp greets Alarm Manager as it walks towards it.
“Hello… Can I help you with something?”, Alarm Manager greets back and asks.
“Yes please, have a look at this” MyApp explains both, the use case and the technical flowchart to the Alarm Manager.
After understanding the flow, Alarm Manager says, “Yes, I can do this!”.
A wave of happiness ran over the face of MyApp.
“How will you achieve this? I mean, How can I implement your methods so that we can achieve the desired result”, MyApp says with excitement.
“Alright, let me explain to you what I can do to you”.
Working of Alarm Manager
Basically, the Alarm Manager works on two types of clocks:
- Real Time Clock: RTC uses “UTC time” i.e; the wall clock time for alarms. This clock depends on the current locale and time zone.
- Elapsed Real Time: is the “time since device boot”. This is not affected by the locale or time zone. It is suitable for the alarms that vary in time.
Each Clock type has a “wakeup” variant, which wakes up the device CPU’s when the screen is off. If you do not use this type of alarm, the set alarm will be triggered the next time the device wakes up.
When the device screen is off for a period of time, then the CPU release resources and goes to partial sleep mode to save the battery. This means much of the tasks stops working like data sync, alarms, network access etc… whereas, a batch is made of these tasks.
Periodically, the CPU wakes up and gather resources to complete the tasks that were scheduled for the instance when the CPU was sleeping.
The wakeup alarms are capable of waking up the CPU and execute its task. Afterward, the CPU goes back to sleep again.
Wake-up alarms are however heavy on power consumption. Therefore, try not to use these alarms until there is a special need.
Based on the above clock and wakeup variants,
Alarm Manager provides 4 types of alarms:
- RTC: Fires the Pending Intent (Direction to perform an action) at the specific time but does not wake up the device.
- RTC_WAKEUP: Wakes up the device to fire the pending intent at the specified time.
- ELAPSED_REALTIME: Fires the pending intent based on the amount of time elapsed since the time of device boot but do not wake up the device.
- ELAPSED_REALTIME_WAKEUP: Wakes up the device to fire the pending intent after the specified amount of time has elapsed since the boot of the device.
“then which alarm type shall I use?” MyApp askes Alarm Manager.
“You may choose between RTC or RTC_WAKEUP but remember that the latter is heavy on battery usage and may drain the battery of your device quite fast.” Alarm Manager replies with the warning.
For further reference visit the Alarm Manager official docs.
“Alright! thank you for the help. I’ll Implement and sort this out myself”, MyApp thanks the Alarm Manager and leaves.
Scene 6: MyApp’s Console
Now, MyApp knows the complete procedure and the components that it needs to implement to achieve the desired.
The very first thing is it makes the UI of the app which looks like this.
On the click of button CREATE JOB, the app has to store the data in these fields into the SQLite DB.
When it creates the tables in the SQLite DB, then it came to know that there is no data type of Date in SQLite.
In SQLite, the data can be saved in either TEXT, INTEGER or REAL. Hence, the very first obstacle is to convert the Date Time entered by the user into the appropriate format.
MyApp decides to convert the Date into String (TEXT) format using the java Simple Date Formatter class.
Till here, the data is saved successfully inside the SQLite DB.
Now, it creates all the three threads that are defined in the flow diagram.
Finally, MyApp implements the Alarm Manager with the RTC_WAKEUP flag.
Each time the job is found and time is updated in the scheduler it also gets updated with the updated time.
Now, the MyApp is ready to be tested for it’s working.
Scene 7: Testing
For the testing, a job is scheduled with the frequency every hour as below:
And the jobs runs exactly at the scheduled time and updated the next time in the database. Furthermore, the alarm is also updated for the next time. According to the above image, the job first ran at 07:42 PM and then, the time updated to 08:42 PM.
MyApp is waiting diligently for the next iteration. And yes, it ran for the next iteration also.
“Hip Hip Hurray!”, MyApp shouted with joy as the task is finally completed and the jobs are running as expected.
“Don’t be so over excited! Let this job run over the night and let’s check if it is really working”, The tester says to MyApp.
“Yes, why not! I believe it is correct. But for your satisfaction, let it run forever”, overconfidence can be seen clearly in the tone of MyApp.
Delighted MyApp was not able to sleep that night.
What happened the next day?
The next day, MyApp wakes up and rushed towards the logs to check out the status of the job. But, as soon as it opens the home page, its face turns pale.
The job is stuck somewhere at midnight.
It was not able to understand anything that happened. When the task ran for 2 iterations then why it didn’t after midnight.
It was constantly thinking that what it will say to the tester. “Last night I was so confident about it. I never knew this would happen. In the future, I’ll make sure to test thoroughly before providing the build.” MyApp murmured to itself.
Meanwhile, Tester enters the scene and asks,“hey! show me the logs. Is it still running?”
MyApp didn’t have words to answer the tester. On the other hand, Tester understands the scenario as soon as it sees MyApp Quiet.
“hahaha…!” Tester laughs out loud and says,” See… I said this yesterday itself that it is not gonna work. Kid, go and do some study”.
*Every Developer know how kind and gentle Testers are 😛
Scene 8: Third meeting with Android OS
Again, MyApp is on its way to meet Android. This time the feelings were different. Its mind is full of thoughts and questions. Anxious, distressed MyApp reaches Android’s place.
once again it found Android busy. But this time there is a difference in the tone of MyApp from what it was before.
“Hi, Android. I want to talk please leave that task.”
“What happened? you look worried. What’s wrong?”, Android leaves its task and comes closer to MyApp.
MyApp: “As you said I went to the Alarm Manager and it said that It can do the task. And yes it did.
The every hour job ran for 6-7 iterations and then it stopped for no reason, if there is something wrong with the logic then it must not have run for these much iterations. And if it does, then why it stopped?”
Android: “What vas the version of Android in the device on which you are installed?”
MyApp: “It’s Android 6.0 ‘Marshmallow’.”
Android: “Did you tried on other devices that run on the version below Marshmallow. like lollipop or KitKat?”
MyApp: ” No, until now just this device.”
Android: “Obviously, the device was left unused at night and was not accessed the whole night.”
Android: “Then the app must be on standby as it was left unused”
MyApp: “I know about the App standby. I took care of this and I have acquired the wakelock permission which doesn’t let me go on standby. So. this must not be the case.
Android: “Hmmm… Then the reason behind is the DOZE mode. I believe you have not heard about it”
MyApp: “No I didn’t”
Android: “Let me explain it to you”
There are certain differences between the App standby and Doze mode. The picture below depicts the difference between the App standby and Doze mode.
The App Standby is triggered when
- The user has not launched or used the application in a long while
- The App has no active foreground service or activities
- There are no pending notifications related to the application
The App Standby ends when
- The user launches the application
- The device is plugged into the charger
- Alarm scheduled by the alarm manager is triggered
Characteristics of App standby
- Restricts background syncs or services of the app that is in standby
- App standby is limited for the particular app that is not in use for a period of time. Hence, it does not affect other apps and the device is in the working mode as usual.
Doze mode is triggered when
- The screen of the device is off for a long time
- If the device is not plugged into the charger
- If the phone has been stationary for a while
doze mode ends when
- The user moves the device
- The user turns on the screen of the device
- The device is connected to the charger
Characteristics of Doze
- Conserves battery
- Restrict network access to apps/ CPU-intensive services
- It defers jobs of JobScheduler, syncs of sync adapter and standard alarms
- The system ignores wake locks
- Periodically run a maintenance window.
- After completion of the maintenance window, the system again enters the Doze mode
- The system does not perform Wi-Fi scans
MyApp: “Can you please explain more on maintenance window?”
- periodically, the system exits doze mode and let the applications do their pending work
- During this maintenance window, the jobs and syncs that were deferred are executed
- Furthermore, the alarms that were delayed are triggered
- Network access is allowed to the application
- Over time, the maintenance window occur less and less frequently
For further reference visit the App standby and Doze official docs.
What happened in your case is this:
Now, as you know, alarms get deferred. See your flow diagram.
Suppose, the scheduled alarm was for 10:00 AM and the system is in doze mode. This means that the alarm is deferred. Let the alarm is delayed by 2 min. That is the first thread (service in this case) will start at 10:02 AM. It will then iterate the DB for the job at 10:02 AM but the job is in the DB is for 10:00 AM. Hence, it will not find the job in the DB and the condition of system time = start time will be false and the thread ends. Hence, the job is not running.
MyApp: “Then what shall I do now?”
Android: “As in the doze mode official doc you must get the answer i.e; you have to set the alarm via the method setExactAndAllowWhileIdle. This will allow the alarm to exit the device from the doze and run the thread at the exact time.”
MyApp: “Thanks for the Explanation. I’ll do this and test. Also, I’ll go through the doze docs and try to optimize myself according to it.”
Scene 9: implementation and final testing
MyApp changed the setExact() method of the Alarm Manager to setExactAndAllowWhileIdle() with the same RTC_WAKEUP flag.
After then it tested the application over the night and over the day and found that the app is working completely fine. The alarms are not getting deferred now.
In the end, MyApp gets completed and achieved what it was meant for. Also, during this implementation, it got to know a lot about how the Android is working to save the battery power of the device.
A Question from the Reader
The flow to which MyApp adapted is the best that it figured out according to its experience.
If you’d have the same use case flow then what would be your strategy to do the task exactly on time? (Remember, time is a critical component).
With this, we come to an end of this tutorial on “SCHEDULER: The story of an immature Android App”.
However, suggestions or queries are always welcome, so, do write in the comment section.
Thank You For Reading!!!