In the beginning there was only the main thread, no apps, and no smartphones and developers were happy. Then we got Android and Google created the AsyncTask and developers were content but there were many Context leaks. The main thread in our apps suffered from hard work and we struggled with runOnUiThread().
After some time, Google decided to award our hard work with Loaders, and there was much confusion. Despite some beautiful preaching from Google, we now struggled more than before and gained less. The main thread kept suffering and there were too many ContentProviders.
Next came the dark ages, where various GitHub projects appeared promising the salvation from all things asynchronous. There were many event-buses, BroadcastReceivers and Executors. All were false prophets who mostly caused more tech debt while trying to gain at least a moment in the spotlight of open-source celebrity. Our main thread kept working and there were many ANRs.
The time had come to look back at the old preachings, and a writing from a man in a colourful shirt gained popularity. It was the time for Reactive Streams and our lives suddenly started to brighten up significantly, or at least it seemed that way (some claim that the colourful shirt is to be blamed). We now had streams, operators, schedulers, subscriptions, and there were many leaks. The high priests of reactive streams acknowledged our despair and updated all their teaching to a second level. We now had everything from the old preachings, but also back pressure. The main thread was too busy to notice and there were many switchMaps, concatMaps, flatMaps, and maps (but not cache, we were not allowed to use that and it was punishable by StackOverflow downvoting).
Our language had changed and the new one was named after an island, and from its origin came an updated version of a very old teaching. This was not threads, but almost, and yet not really. It was time for Coroutines and we once again had too many preachings and writings. There was, again, much confusion. But once things started to settle, it looked for a while like we finally found a solution to all our struggles. Even the main thread was cautiously optimistic, although it still had too much to do.
But new problems appeared. The ViewModel (which is not a View Model) wanted its share of these, and yet it was not in control of its lifecycle as that belonged to the Activity. There was much struggle and from the roots of coroutines grew the scopes and contexts. We learned about dispatchers and jobs, actors and producers. There was more confusion. The main thread knew that things wouldn’t change and kept working, but at least we didn’t have ContentProviders anymore (unless you count the years of technical debt or the “right” way of doing Dependency Injection).
Our struggle doesn’t end here and nobody has yet been able to provide us with a simple and safe way of working with threads, and we don’t know what the future holds for us.
Until the time when such a tools will be invented, the main thread keeps working as hard as it ever has, while streaks of tears are flowing down its call stack.