As all other User Interface Platforms – Android also has the same concepts about graphical user interfaces. There is a User Interface (main) thread that handles user interactions and every non-UI operation – especially input/output – should and must be executed onto another thread, otherwise the user interface will freeze, feel laggy and unresponsive or at least slow. There are various approaches of doing this delegation of the heavy work to another thread, so this is what I’m gonna describe in this articles.
First lets start with the Android System – Visual (and non-visual) Components.
This is one of the core components – for displaying data to the user on the screen. On the more recent versions of Android or even Chrome OS – the portion of the screen that the system delegates to the Activity could be half of the screen or even fixed or floating window – similar to the normal desktop and on the older versions of Android – the system gives you possibility to do whatever you want visually on the whole screen – with or without the notification area depending on an attribute in the configuration.
Fragment is something between a view and an activity. It has the lifecycle events of an activity, it could theoretically occupy all the screen, but it also may take only portion of the screen.
If you do not want to paint everything yourself, which is heavy work – you could use the system provided views, mix them up and create your own views or use some library – like the material design components. A view is just like the flutter widget – it could be display only – showing some information or it could have a state and behavior and so on – depending on repeatability of the UI components and the complexity you want to go into.
Screen widget – the Android System gives you the possibility to setup visual components that are designed to be placed within the Main Android UI (also called launcher), that could change dynamically – displaying some information differently depending on your app data and could have even some functionality – escaping the need to launch a whole application (Activity) – to view some info or do some thing. As such – there are restrictions to what visual components (Views) you may but nevertheless – it is cool addition.
Notification – very much like the screen widget, but with location of the visual component – the notification bar. Google is adding possibility to add features and actions and interactions within the notification with almost every version of Android
Non User Interface Components
Service – The Service is Android System component that is part of an app, but it is not attached to any screen (activity). Be aware that it still is executed on the Main UI Thread of the app so – don’t do stupid things on it directly. Several of my apps needed at some point – that I should have anticipated – to migrate the non-dependent to the back-end work – the screen to change the local database and the service to execute the actual synchronization requests. That how – the user is not stuck to the screen of operation. From Android 8.0 and above – with the increase of importance of privacy – Google enforced some restrictions. The Service component may run without the user being aware of it – while the user is on any of the screens of the app. If the users goes out of it, the service has limited time to finish work and stop or to pin (or attach) to a notification – so the users could know that application X is doing something.
Broadcast Receiver – Is an Android component for implementing publish/subscribe design pattern. It is based on a String (topic), but also you could add some key/value parameters that need to be matched so a BR to be triggered. On which Thread it will be processed – the Main Thread or a background Thread – depends on the subscription. More about it below. Many of the Android System events could be detected within your app by receiving the permissions from the user to do it and by subscribing to them – OS Boot Finished, Internet Status Change and many more.
What is tricky about all the above components is – they are all executed on the Main – User Interface (Java) Thread. If you wanna execute any meaningful work, it should be off the main thread. This includes heavy mathematical operations, writing to the local file system of the device, opening connections and writing to Wi-Fi (HTTP requests), Bluetooth, and other types of outbound sockets including – connected to the Android device hardware and more.
Thread – The Android Platform and Framework is based on Java – The Virtual Machine, APIs, concepts and more. No matter what other layer you put above it. You will not be able to escape the deeply rooted architecture principles. You may code your app in Java, Kotlin, You may go aside with Flutter or React Native. You may even not see it directly and have no idea – the same thing may be implemented in C/C++/Go/etc for the purposes of a custom UI Framework – but somewhere, someone does the plugging in with the Android System and it’s with the above (and below components).
So – in Java GUI development – there is a AWT Thread that handles GUI changes – by user interaction or received from other threads. Similarly in Android – there is a Main Thread that is hidden but ever present and the One – on which every user interface component is running on. While going through some work on any of the components you could create a Handler from them and use it from the non-ui thread – to queue and give to the User Interface Thread some work to be executed onto the User Interface.
Handler – It is like Thread Executor. It manages the soft multitasking behind every app and it has the utility functions to glue and connect the User Interface Thread with any other non-User Interface Threads.
Broadcast Receiver – The broadcast receiver components could be used as a background execution jobs by attaching them to the Android Application (Context) with handler – different from the Main one.
AsyncTask – It is the equivalent of SwingWorker. It is an upgraded Thread that has one important method for doing the things in the background and several methods that are executed on the Main Thread. onProgressUpdate (on the Main Thread) – is triggered by publishProgress – with the ideas to put an intermediate result of the work – useful when the operation is heavy and onPostExecute/onPreExecute – to do something after/before execution. It is being deprecated because it was used a lot and it doesn’t enforce the developers to take into account the life-cycle of the Android Component that it runs on. That’s why it created a lot of bugs.
Live Data – Because getting whatever source code component should be Life Cycle aware – Google made an Architecture Component that receives or listens the life-cycle events. Wrapping up whatever work in Live Data and plugging – the Live Data to the User Interface – not the work and the result of it – makes the code bug-free.
Co-Routines – I see it like mix of Live Data, Async Task and Broadcast Receiver (when its about GUI reaction) – Google migrated to Kotlin Programming Language which gives a lot of more possibility of expressiveness, domain specific language and more. They wrapped all the above different APIs for messing up with threads and different components in a functional less-invasive API. That doesn’t mean that the everyday developer should not care about what is beneath the Kotlin DSL code, because there will probably be cases when – not knowing the core may create bugs, but – for simple, small jobs – they will make the code more readable and clean.
Work Manager – It is a new and improving API – Architecture Component – for replacing – the Android Service, Alarm Manager, Broadcast Receiver (when used as a Job/Task component), that will probably take into account the restrictions of the System on Services, the device time off and many more improvements within Android for improving battery life and privacy. I haven’t dived into it too much as my latest projects I’m writing in Flutter but if I ever go to do native Android, I’ll probably need to check it out.