Android App Architecture - An Overview Of Async
Written by Mike James   
Monday, 07 November 2016
Article Index
Android App Architecture - An Overview Of Async
Android Concurrent Programming

Android apps are surprisingly complex in their nature and they have a well developed library of classes to help you create them. Many Android programmers are so close to their subject matter that they don't have time to stand back and admire the view. In this opening chapter from our forthcoming advanced Android App Architecture book we examine the scene from 1000ft up. 

 

Android App Architecture

  1. Android Architecture - The View From On High
  2. More than one Activity
  3. Intents
  4. Services
  5. Basic threads
  6. AsyncTask
  7. Event Queues
  8. JobScheduler
  9. Concurrent Services
  10. Content Providers

 

Android App Architecture

If you have written even one  Android app then you have encountered the Activity. In many ways the Activity is like a web page. You can write an app with a single Activity class and it will display, usually, a single UI as its View. By analogy with a web app an Android app can be composed of more than one page. The usual way of doing this is to create an Activity, complete with a View implementing a UI, for each "page". 

The whole point of building an Android app using multiple Activity classes is to organize it. By having one Activity per View you can also take advantage of the Android system's back stack. This keeps track of the Activities that the user has interacted with and allows the user to navigate back through them to return to an earlier state - just like the back button of a browser. For example, you might implement an app that has an initial starting UI Activity that allows the user to select a data entry or data viewing option. Each one of these could be implemented as an Activity with its own View implementing the specific UI. The use of three Activities complicates the overall design because you have to deal with creating and running them and with inter-Activity communications. This said, the reward is that you can work on each Activity in relative isolation. 

  • Multiple Activities compartmentalize and organize your app.

Even though it is generally regarded as a good idea, you don't have to create apps with multiple Activities. You can opt to create an app with a single Activity and arrange to present different Views depending on what you want to show the user. This is not how most Android apps are structured.

Once you have the general principle of dividing up an app into components for organizational reasons, it isn't difficult to think up some additional types of component. Android has four basic components

  • Activity
    Used to present a View to the user and generally manage the UI
  • Service
    Basically an Activity without a View and used to implement tasks that don't directly involve the user
  • Content Provider
    Used to provide data to other components
  • Broadcast Receivers
    A component that is only used to respond to system-wide announcements

You can see that these four components can be used to make a fairly sophisticated division of responsibilities in a complex app. To make it all work we have to find out how to start new components and how to manage them. We also need to find out how to pass data between them. All this wil be cover later in this book.

This is usually where the account of Android program structure comes to an end but over time things have become finer grained than the big four components. There are a number of components that can be used within an Activity to compartmentalize it. The best known is the Fragment, which is a bit like a lightweight Activity. It has a View, but unlike an Activity a Fragment doesn't display its own View. Instead the Activity that the Fragment belongs to hosts its View. In this way Fragments provide a way to break up what would have been a single Activity and View into sub-components. 

If a Fragment sounds a bit like a dialog box to you, then you would be correct and it is the basis for implementing dialog boxes that pop up on the screen over the Activity's UI. That is, in a modern Android app even the Activity can have structure by being decomposed into a set of Fragments and Dialogs. 

When you build a complex app you need to have a blueprint for how you are going to decompose it into the different functional components that make it work for the user. For the UI this is often fairly obvious because it corresponds to the different screens you want to show the user and the data that you want to get from the user. Where it is often more difficult is when we move away from the UI and implement the work that the app does in code. 

The Problem Of Threading

When you first start to create Android apps you start with an Activity and build a UI by implementing a View usually specified in an XML resource file. All of this is covered in my Andriod Adventures With Android Studio, now revised and updated and published in book form as Android Programming: Creating A User Interface and now we'll build on this foundation.

This sounds similar to other application frameworks and you might think that all you have to do now is carry on implementing the logic of your app in the Activity. However, there is a problem with this approach. You usually cannot code all of your application's logic into the onCreate event handler or any other event handler. The reason is very simple - if you write lots of code to do some task or other in any of the event handlers then the user interface will become sluggish and eventually freeze.

So what is a thread?

A thread of execution is the sequential execution of the instructions in your program. A modern processor will have multiple cores which can each run a single thread. This means that more than one program can be running at the same time. However, things are slighly more complicated in that there can be many threads active and the processor will switch from one to another. It's like reading more than one book at a time. You read a few pages, stop and bookmark the spot, read some of another book until you stop and bookmark where you got to and perhaps resume reading the first book from the bookmark. This is what a processor does, but so fast it looks as if the both threads are making progress though their respective programs at the same time. 

When you start an Activity it is assigned a thread of execution usually called the UI thread. Its only purpose is to serve the UI. When the user clicks a button, say, and the OnClick event handler is called the UI thread is occupied and cannot respond to any other events until the OnClick event handler returns. 

What happens is that most of the time the UI thread is doing nothing useful. It simply waits for an event to occur and then it executes the corresponding event handler. If another event occurs while the UI thread is dealing with the OnClick handler then the event is added to a queue and the UI thread deals with it when it finished with the OnClick handler. The entire time the UI thread is simply reading events from the event queue and executing the approriate event handlers. 

Now consider what happens if one of the event handlers does something that takes a long time. The UI thread is occupied and as the user interacts with the UI other events are added to the queue, which gets longer and longer. In the worst possible case, if the event handler keeps the UI thread busy for a few seconds, the Android system will notice and it will assume that the app has crashed and it will stop it because the UI is frozen. Even if the UI thread is only kept busy for a relatively short time, it can means that the event queue isn't serviced and grows longer, with the result that the UI becomes sluggish and unresponsive. 

The rule is that if you want to create an app that has a responsive UI, making it a pleasure to use, you have to make sure that your event handlers return as quickly as possible. It is the paradox of this sort of programming that the ideal state for the UI thread is doing nothing at all so that it is ready for the next event as soon as it occurs. 

Of course, you can do quite a lot of work in an event handler before it starts to slow the UI down but as soon as you have to do anything that takes significant time - like downloading a file, looking up something in a database or performing a difficult iterative calculation, then you cannot burden the UI thread with it. 

What this means is that your Activity and its View are just there to create and service the UI rather than do any useful work. 

So how do we get useful work done in an Android app?

The answer is that we have to use additional threads. 

Given that we have just introduced the idea of using more than one Activity in a program perhaps this is the solution. Why not start another Activity to do the long running task and have the original Activity look after the UI?

This doesn't work for a very simple reason.All of the Activities you create run on the single UI thread that the main Activity acquires when it starts. In plain terms what this means is that there is only ever one Activity running at any moment.

When the main Activity starts another Activity it is stopped and added to the back stack to be restored only when the user clicks the back button. The currently running Activity uses the UI thread and is subject to the same requirements of not giving it so much work to do that it freezes the UI. 

Often the next thought that occurs as a solution to the UI thread problem is to use a Service for the long running work. After all the documentation describes a Service as

"an application component that can perform long-running operations in the background"

You will also find descriptions of the Services behaviour like:

 "the service is started and can run in the background indefinitely."

The fact of the matter is that a Service runs on the same UI thread that the main Activity runs on. That is, if the Service does something that takes a long time the Activity doesn't get a chance to update the UI and the result is that the UI freezes.



Last Updated ( Monday, 11 June 2018 )