JetPack Android WorkManager Library - some details under the hood 👷

\n Malyshev Yegor \n
AndroidPub
Published in
7 min readMay 10, 2018

Hi everyone ⊂( ◜◒◝ )⊃,

so lots of articles basically show APIs from a bird’s-eye view, but for such purposes, I would rather explore documentation first. That’s why today I want to show you a short explanation what lies under the hood of new Architecture Component that has been announced just recently at Google I/O 2018 and I am talking about WorkManager from JetPack.

Top layerヾ(゚∀゚○)ツ

So, before any use to make it work you have to prepare your environment, namely include the right dependency and you are good to go:

implementation "android.arch.work:work-runtime:1.0.0-alpha01"// if you want some benefits from Kotlin then try this
implementation "android.arch.work:work-runtime-ktx:1.0.0-alpha01"

Now let’s create some Work quickly and start it:

So, looks pretty. But wait I’m a bit busy (or just work “hardly”) and want to stop my hard work right now. And yes we, of course, have such method:

As you can see here we use a method called cancelWorkById(UUID). There are other methods to stop your particular work or chain of works or whatever (by tags or by unique name). Because we don’t generate it on our own there are possibilities (see below) that collision will happen and if you start some really important job and then start some plain unrelated job and want to stop it but UUID is the same for both therefore bad things will happen (tip: use tags if you care).

From Wikipedia it seems like almost impossible to have a collision but it also means that we can’t fully rely on it… Also, I’m not sure why the method to retrieve UUID returns the actual object. I think such details should be hidden. Also as a solution to have some guarantees the generation process could be changed to something like this: currentTimeMillis + '-' + UUID. Meow? Anyway Google’s guys know what they do and do their job well and I’m serious here.

Middle layerヾ(゚∀゚○)ツ

So, maybe you think that I’m going to just list all methods and explain them… Sorry but not. The documentation is pretty nice for Architecture Components and it’s boring to explain it again here. Let’s try to find out some interesting details. In short, WorkManager is here for some reasons but mostly it’s like JobScheduler or similar libraries. What kind of reasons? I think there are at least three major reasons:

  • Backward compatibility. Before it, we weren’t able to have one solution for everything (of course I’m wrong and there were some but not directly from Google).
  • Monitoring, observability. What does such math words mean here? It means that at any moment you are able to know what happens with your work, see current outputs, monitor it. Yeah, it was possible (hardly) for some solutions but it wasn’t so easy as here.
  • Guarantees. It means that whatever happens your work will be performed.

and there are at least three things (please explore them using coming video from Youtube or documentation) which differ it from other competitors and for sure it’s awesome:

  • Inputs (provide input data for works) / Outputs (set output data for works). Using In/Out mechanism you are able to pass data from chain of works to some major work or whatever scenario you think about. Also to deal with conflicts you are able to provide your own merger! The only one thing that should be considered carefully it’s a size of your data. Looks like it’s about 10 KB (maybe yes and maybe not it depends you know). But I think it’s a reasonable choice of course and calculated carefully too. Niceeeeee.
  • Chained works. Just imagine that you are able to run 3 works in parallel and only then compute something based on the results from them and then upload your results somewhere else and provide conditions to deal with battery and networks!
    Sweeeeeet.
  • Unique works. For instance you have 3 different triggers in your system but you want to do the same work for each of them and of course we want to do it once but react on all of them and if some is already enqueued then you want for different reasons REPLACE (start new one and forget about old one) / APPEND (let it finish and start a new one) / KEEP (let it finish and skip the current) it. Yay! We have such ability. Just create a unique work, provide some unique name for it, provide a work policy when you schedule a work with the same name and schedule it. Then you are able to schedule your new unique work with the same name and WorkManager will solve your problem like a piece of cake.
    Awesoooome.

✪ Backward compatibility:

Above you are able to see the source code (even if it’s in Java there I convert it to Kotlin to keep everything consistent, sorry) from the library itself. Everything is easy here, two main schedulers are created.

First is the best of the best:

Second is for instancy (if a phone is active enough then why not?). So if your work is really simple in terms of conditions and it’s not periodic and there is no start delay for it and when all conditions are met then WorkManager starts it and if it’s done before the same work on the first scheduler then we are good to go. Purposes of it to let your work be done as soon as possible because there are no guarantees when the first scheduler will perform it. Sounds pretty reasonable.

✪ Observability:

As we have already seen above it’s possible to retrieve LiveData object for any of your work (by UUID, tags, names, etc.). Sounds really handy because as we know such observation is lifecycle aware (if you observe properly of course). Also, it’s great because you don’t need to check and check and check and again check it every X-seconds and you will know about results as soon as possible.

Also if you are on some background thread already and you just want to check your status right now and forget about future then we are lucky because all methods (also for enqueuing) are duplicated in a synchronous manner.

Where is the magic? Oh boy… Magic is done via other great things as Room.

So actually we just fetch statuses from DAO and observe them via MediatorLiveData to map our POJOs to the final statuses. Pretty handy right?

Guarantees:

Oh yeah, guarantees it’s one of the nicest things of course. No one would like to live in the unstable world. And here we don’t have any!

As I mentioned above internally Room’s stuff is used to make you happy. So before starting any work, WorkManager records it via Room. Then any time when something should be changed about status, output data, etc., will be handled via Room’s transaction to guarantee that everything is synchronized.

For instance, if your work fails and you set before several attempts for your Work what do you expect next? The following methods will help you to understand the main concept:

It’s pretty crystal clear. Update attempts and continue. But wait! What’s about all input/output data, conditions and my Worker class! And as you are able to see from codelabs (or documentation) everything is eventually kinda Parcelable and it’s, of course, possible to store in Room. Holy-moly, but it’s just about params, what’s about my Worker class? The same story here. As you will see during your journey that actually you don’t have abilities to create something bad and pass it to WorkManager and thus break things. Your related class-name will be stored as well and instantiated when its time will come.

That’s why you have yours guarantees and everything will be done eventually.

ヽ( ´ー`)ノ

Here comes outcome. What do we have? We have a really powerful manager for our works! Actually, I just described the general things which go right underneath the WorkManager. Lots of code there and it smells tasty. I hope that you got the main idea. To see the real example I recommend codelabs because lots of stuff goes there. And yes WorkManager is documented really well. This is how any public library should look. Because it’s still alpha some things can be broken in extreme cases but from my point of view it’s ready at least for your pet projects to taste and to leave some feedback if you find some uncomfortable or broken things.

Probably you are wondering about testing. Don’t worry, it’s JetPack and it has such item: androidTestImplementation "android.arch.work:work-testing:1.0.0-alpha01".

Also please keep in mind that you should use WorkManager for right things and don’t forget to use conditions to make phones happy (battery life, network traffic, etc.):

  • Upload stuff to a server 🍏
  • Process data and store it in database 🍏
  • Don’t use it in order to apply some image filter and display the result in ImageView instantly on the same screen 🍎

Useful links to keep your attention once again:ヾ(・ω・)シ

Thanks for listening. Bye-bye °˖✧◝(⁰▿⁰)◜✧˖°

--

--

\n Malyshev Yegor \n
AndroidPub

Malyshev Yegor aka brainal · Absorbed Android Developer @ Google · Kotlin lover · Sport Programming · Algorithms · Programming · Android · J`world