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

We could repeat the argument with the other components - Content Provider, Broadcast Recievers and even Fragments. The conclusion would be the same.

An Android app has only a single thread of execution and all of its components run on the same UI thread. 

What this means is that how you divide up your app into components has no bearing on the problem of overusing the UI Thread. At any given moment only one component will be running an Activity or a Service or a Fragment. The system calls a single event handler in one of the components and waits for it to complete before calling another event handler, perhaps in a different component. All of the event handlers run on the UI thread and if any of them take too long to complete the UI will freeze and if it freezes for long enough the app will crash. 

This also means that at any given moment there is only one line of code in your app being obeyed. This means that there is no need to control access to shared resources because no sharing is occuring. The single UI thread makes its way through your program in an order largely determined by the events that occur and your program is a collection of event handlers and their helper functions. 

You might ask why Android is built in this seemingly limited way?

The answer is that it is very simple and very safe. With only a single thread of execution in action there is no danger that two possibly conflicting things will happen at once.

There is no concurrency within the system - it is asynchronous but not concurrent. 

Android Concurrent Programming

If using multiple Activities and Services has no impact on the UI threading problem what is the solution?

The answer is that you have to create additional threads of exectution for any long-running tasks that you need. In other words, there is no easy solution and as soon as the app needs to do anything that takes a lot of time you have to explicitly write code that runs on another thread. 

The good news is that the Android system provides some higher level abstractions such as AsyncTask and Handler, but the bad news is that these have their own problems and difficulties. 

In short, creating a robust Android app that makes use of threads and more sophisticated facilities such as Services running separate threads is a difficult thing to do - unless you understand completely the way things work and know what your options are. 

Concurrent programming is usually regarded as complicated and error prone and in most other platforms you are best advised to avoid it if possible. In the case of Android it is virtually impossible to avoid and you have to come to terms with it. Even fairly modest Android apps have to make use of additional threads and it seems likely that not having a full understanding of the way things work is one of the reasons that Android apps have a reputation for instability. 

At this point you should be clear that any structuring of the app that you might attempt - making use of multiple Activities, Services and so on  - is largely irrelevant from the point of view of using additional threads. If you want to, you can create an app that uses a single Activity, possibly with multiple Views and multiple threads to keep the UI thread responsive. There are advantages in making use of Services to host worker threads, but you don't have to use them if you don't want to.

Using multiple threads means that you can move work off the UI thread, but it brings with it a new problem. A worker thread has to deliver the results of its work and this often means displaying something in the UI. To avoid problems of two threads trying to up-date a single UI control, Android enforces the rule that only the UI thread has access to the UI. If you try to access UI components from anything other than the UI thread you will find that you get a runtime error. There are facilities that allow a worker thread to run code on the UI thread and vice versa and you need to know how to do this and generally allow threads to interact safely. 

In addition to all of this there is the small matter of lifetime. It is a feature of Android that the system can stop an app at any time it needs to. This is something of a problem for an app that just uses the UI thread, but it is even more of a problem for an app with multiple threads. Now it is not only the part of the app that the corresponds to the UI and the UI thread that you have to consider when it is stopped and recreated, but also any threads that might be running. This can be a matter of saving intermediate results to that a worker thread doesn't have to start over from scratch, but there is also the problem of what to do about threads that crash or need to be cancelled. Orphaned threads are a common problem and they lead to memory leaks and wasted battery power. 

The bottom line is that using threads properly is a difficult challenge, but unless your app is nothing but user interface you cannot avoid it. 

Stopping The UI - A Demonstration

To get some idea of the sort of behavior we are talking about let's write a small demo that stops the UI and eventually crashes the app.

Start a new Blank Activity project and place a Button and an EditText control on the design surface. Set the Button's onClick event handler to 

public void onClick(View v) {
 int j = 0;
 for (int i = 0; i < 10; i++) {
  for (int k = 0; k < Integer.MAX_VALUE; k++) {
    j++;
  }
 }
 ((Button) v).setText("Finished");
}

To give the handler something to do we have a pair of nested loops. The inner loop runs from 0 to 4294967295 and the outer loop repeats this 10 times which keeps the UI thread occupied for around 30 seconds on the emulator. If you are using a real device, or have a faster machine, you might have to increase the number of outer loops to get the correct delay. 

When you run the program make sure to click on the EditText to get an on-screen keyboard and then click the button. You will find that you cannot enter any text into the EditText until the Button's text changes to finished. This is because the UI is frozen while the loops are executing. What you might be more surprised about is that you can type on the onscreen keyboard and what you type appears along with the predictive text suggestions. The reason for this is that the on-screen keyboard is run on a different thread to the UI - it is an independent application. 

Next increase the outer loop to 100 or more and eventually you will see the warning message from the system: 

ANR

A real application that is overusing the UI thread is more likely to be doing so with a more irregular pattern which causes the UI to slow down rather than freeze completely as in this example. 

The point is that you can't use the UI thread for any task that takes longer than a few milliseconds. Also notice that we would have got the same result even if the loops were in another Activity or a Service. Unless you do something about it, every line of code in your app is run on the UI thread. 

Summary

  • You need to use at least one Activity to create an app but you can use more to provide a structure. Each Activity has its own view and should correspong to a particular interaction with the user - a particular input form say.
     
  • As well as Activities an app can be composed of other types of component - Service, Content Provider and Broadcast Recievers. Again these are largely organizational units for your app but each type does have characterstics that makes it suitable for particular uses. 

  • All of the components that make up an app run on the same thread - the UI thread. This means that at any moment there is a single line of code in your app being executed. 

  • An Android app is a collection of event handlers organized into different types of component. 

  • The purpose of the UI thread is to serve the UI. If you use it for intensive computation or anything that takes more than a few milliseconds the UI will become sluggish and perhaps even freeze. In an ideal world the UI thread would spend most of its time waiting to handle an event.

  • Using Activities or Services does not solve the UI thread problem because they run on the UI thread. To move work off the UI thread you have to explicity create and use addtional threads of execution. 

  • Only the UI thread can access UI components and we need to find ways of allowig other threads to access the UI and to communicate results to one another. 

  • Managing threads and allowing them to communicate with each other is a difficult but unavoidable challenge. 

 

 

 

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

 

To be informed about new articles on I Programmer, install the I Programmer Toolbar, subscribe to the RSS feed, follow us on, Twitter,FacebookGoogle+ or Linkedin,  or sign up for our weekly newsletter.

 

espbook

 

Comments




or email your comment to: comments@i-programmer.info

 

 

 



Last Updated ( Monday, 11 June 2018 )