Skip to main content

A fusion between WorkManager and AlarmManager


Androids' WorkManager has been around for a while. However my own expectations about it were a little higher. I wished that the WorkManager could fire events at exact timing. But since it was made to respect doze mode, I should respect that too. That means that if the phone is idle, the WorkManager wont run. 

Lets explore my case: 

Once the user logs into my app, I need to schedule 5 alarms for him. But the alarm times come from a server and not locally. So basically I need some background work to do: 
Sync timing -> Save to database -> Schedule Alarms. (btw on the time alarm will fire, it's just a notification to be shown)
Now this has to happen every day at 00:01. The data coming from the server hold the alarm timings for a year, but certainly I can't schedule alarms from current moment till the end of the year. It would drain phones battery. So I need to start a
WorkManager to save data to my local Room database and after that I need to repeatedly  schedule alarms every day.

On with the show: 
First of all, if anyone is curious why I chose WorkManager over JobScheduler or even BroadcastReceiver

1- Don't have to register nothing to the Manifest file.
2- Don't have to worry about internet connection, phone reboot etc.
3- I faced lots of deprecated methods and constants without it.

Let's start:

So the WorkManager has a few things to set up. Since I will get data from API, I need my worker to be started if and only if there is internet connection which is specified by the setRequiredNetworkType(NetworkType.CONNECTED) method in the Constraint.Builder(). After that I need to specify how many times will my worker run. On my case there is no comment needed looking at the name OneTimeWorkRequestBuilder which has a worker of mine. After setting my defined constraints I can start my DataSyncWorker.

Let's check the class now: 

Since I love coroutines and I am using them everywhere, I am using the WorkManager by extending CoroutineWorker. So the method where all my sync happens is named doWork which btw is a suspending method handled by the Android framework itself. By the way is hell lot of data. 

And now, lets jump into my OfflineScheduler


Looks like I'm done scheduling my notifications at current timing for today and also tomorrows timing alarm, which will schedule other alarms:


Once the alarm has been set, Android "waits" until the time comes and brings my code here:

And another one which was scheduled for the midnight, which basically will trigger my OfflineScheduler code again:

And it will fire and fire until the end of time 💪

There are 2 more things:

First of all, for the classes extending BroadCastReceiver to work, need to be registered to Manifest file.
And second of all how do I schedule my notifications whem the phone reboots? 👀

So I made another Receiver which only needs to be registered on the Manifest and nothing more:

Now this one needs a small modification achieved by a boolean flag. What happens if my worker has never started and I request to schedule local data (which never arrived)? A total disaster.

And pretty much that's it. That's the best combination I could do to solve my case, and if you have other suggestions about my case, feel free to comment.

Popular posts from this blog

Modularizing your Android app, breaking the monolith (Part 1)

Inspired by a Martin Fowlers post about Micro Frontends, I decided to break my monolithic app into a modular app. I tried to read a little more about breaking monolithic apps in Android, and as far as I got, I felt confident to share my experience with you. This will be some series of blog posts where we actually try to break a simple app into a modularized Android app.

Note: You should know that I am no expert in this, so if there are false statements or mistakes please feel free to criticize, for the sake of a better development. 

What do you benefit from this approach:
Well, people are moving pretty fast nowadays and delivery is required faster and faster. So, in order to achieve this, modularising Android apps is really necessary.You can share features across different apps. Independent teams and less problems per each.Conditional features update.Quicker debugging and fixing.A feature delay doesn't delay the whole app. As per writing tests, there is not too much difference about…

From Gson to Moshi, what I learned

There is no doubt that people are getting away from GSON and I agree with those reasons too. The only advantage GSON has over other parsing libraries is that it takes a really short amount of time to set up. Furthermore, the most important thing is that Moshi is embracing Kotlin support.

First let's implement the dependency:
implementation("com.squareup.moshi:moshi:1.8.0") It's not a struggle to migrate to Moshi. It's really Gson look-a-like. The only thing to do is annotate the object with @field:Json instead of @SerializedName (which is Gsons way for JS representation):

data class User( //GSON way @SerializedName("name") val name: String, @SerializedName("user_name") val userName: String, @SerializedName("last_name") val lastName: String, @SerializedName("email") val email: String ) data class User( //Moshi way @field:Json(name = "name") val name: String, @field:Json(name = "user_name…

Modularizing your Android app, breaking the monolith (Part 2)

This is part 2 of a series of articles about modularizing Android app. If you haven't yet read the first article, you may find it here.

On our first article we just moved some classes outside the application and applied as an independent module. But what if we have dependencies pulled from the application level? This could be a small challenge. First of all, we want to clarify on how are we going to modularize the app. And depending on the previous article, I chose the by feature version of modularization. First of all, let's show some dependencies that are going to be needed in the whole app.

Note: I'm using Dagger for handling dependencies but manual DI or any dependency tool should be fine to understand this part.

So, this is my dependency schema:


Well, it's not that bad, but this isn't what we want to transform to when trying to modularize the app. If you think about it, modules that don't need a dependency, can get it quite easily. For example: A FeatureXVi…