Background Work in Xamarin.Forms. Part #1 — Xamarin.Android
What should we select if we need to run some work in the background? Should it be a Worker, Service or simple Task Run from .Net? Let’s find out!
Hello Folks 👋!!! Sometimes our Mobile Applications have to do some work, not in UI Thread, some long or short work, periodic or one-time-only, work where we need to ensure that it will not be suspended or it can be finished when the app is terminated. Android and iOS systems provide quite different ways for all that work, depending on what resources we want to allocate during Background Work. In this article, we will focus on Android only. To iOS, we will back in the second part of this article which will be published soon.
In this article we will take a look and compare the next ways to run work in Background, we will try to face all pluses and minuses on each of:
- Task.Run — .Net Native way to run work in Background Thread
- Worker — the recommended solution for persistent work in Native Android Apps
- Service — an application component that can perform long-running operations in the background
Here we have multiple options, depending on how many and how different our work is, we can register multiple interfaces and run multiple services/workers. But for our example, we will have one general interface with the work Func<Task>
, and we will use IoC Container from MvvmCross for Xamarin.Forms NuGet Package.
In Android, it’s not so important what we will do in the background, so let’s assume our Task
will check out the database and try to push unsynchronised changes if we have an internet connection. Again, it’s too simple to show this part of code, so imagine that we do that in the right way with all SOLID Principles and so on.
ℹ️ Work Manager may run Scheduled/Repeated Work when app is closed or Terminated, but Android system does not guaranteed that 🤨 🧐, yes it’s not guaranteed, actually never worked for me as expected but I found that for someone at StackOverflow it was worked.
Android Background/Foreground Service
Before we start, let me give you a link to official documentation, and we are ready.
Firstly let’s define a general worker who will start Background Service. Yes, it can be the same class, same as it can be two different. Service will connect two different classes through DI and Interface registered as Singleton in my example. In your code, that can be one interface and one implementation inherited from the native Service and your global Interface; it’s up to you 😋
Service itself can be background if SDK < 26
or foreground if SDK is higher. But each service requires a building a notification tile, which will represent to the user what actually it’s doing. In my example, I used the AppResources RESX File to hold all my localised strings.
At first we need to create and Intent with proper Activity Flag
(in our case it’s ActivityFlags.NoUserAction
). Then with Notification Builder
we need to set title and description text with icon and color from Android Resources.
If SDK is 26
or above, we also need to Notification Channel
, where we can set lights, vibration, importance and other options.
Android Worker with WorkManager
This work is quite similar to Task.Run in most cases when we need to make some work immediately in the background. But if we need to create repetitive work or some specific long time work this is the recommended solution.
WorkManager handles three types of persistent work:
- Immediate: Tasks that must begin immediately and complete soon. May be expedited.
- Long Running: Tasks which might run for longer, potentially longer than 10 minutes.
- Deferrable: Scheduled tasks that start at a later time and can run periodically.
The Result
returned from doWork()
informs the WorkManager service whether the work succeeded and, in the case of failure, whether or not the work should be retried.
Result.InvokeSuccess()
: The work finished successfully.Result.InvokeFailure()
: The work failed.Result.InvokeRetry()
: The work failed and should be tried at another time according to its retry policy.
It’s really useful to add some logger to get in-app centre some results of a real app used on different devices and log how our workers actually do work. Also, you may wonder — Why I’m waiting for a task
? Because we are already in Background Thread managed by Android OS and have time-to-time problems with async/await
, I would like to return the work result
only when it’s ending.
To run our job, we set up required start-up constraints and intervals in case of periodic work. More about result policies and observable status of our workers you can read here:
https://developer.android.com/topic/libraries/architecture/workmanager/how-to/states-and-observation
Old Good Task -> Run
Here is a cross-platform implementation with good old Task.Run
is a perfect solution if you just need to run some code in a background task while the app is working. I think there is nothing to explain only add if you want to wait for some reason you can easily change void
to Task
Thanks for reading; I hope it was useful for you. Please follow me here on Medium and also in my Twitter account