Search icon CANCEL
Subscription
0
Cart icon
Your Cart (0 item)
Close icon
You have no products in your basket yet
Arrow left icon
Explore Products
Best Sellers
New Releases
Books
Videos
Audiobooks
Learning Hub
Conferences
Free Learning
Arrow right icon
Arrow up icon
GO TO TOP
Asynchronous Android Programming

You're reading from   Asynchronous Android Programming Unlock the power of multi-core mobile devices to build responsive and reactive Android applications

Arrow left icon
Product type Paperback
Published in Jul 2016
Publisher Packt
ISBN-13 9781785883248
Length 394 pages
Edition 2nd Edition
Languages
Tools
Arrow right icon
Authors (2):
Arrow left icon
Helder Vasconcelos Helder Vasconcelos
Author Profile Icon Helder Vasconcelos
Helder Vasconcelos
Steve Liles Steve Liles
Author Profile Icon Steve Liles
Steve Liles
Arrow right icon
View More author details
Toc

Table of Contents (14) Chapters Close

Preface 1. Asynchronous Programming in Android FREE CHAPTER 2. Performing Work with Looper, Handler, and HandlerThread 3. Exploring the AsyncTask 4. Exploring the Loader 5. Interacting with Services 6. Scheduling Work with AlarmManager 7. Exploring the JobScheduler API 8. Interacting with the Network 9. Asynchronous Work on the Native Layer 10. Network Interactions with GCM 11. Exploring Bus-based Communications 12. Asynchronous Programing with RxJava Index

Android primary building blocks

A typical Android application is composed of the following four main building blocks:

  • android.app.Activity
  • android.app.Service
  • android.content.BroadcastReceiver
  • android.content.ContentProvider

The Activity, Service, and BroadcastReceiver are activated explicitly or implicitly over an asynchronous message called Intent.

Each of these building blocks have their own life cycle, so they could be exposed to different concurrency issues if an asynchronous architecture is used to offload work from the main thread.

Activity concurrent issues

The Activity building block has a tight connection with a presentation layer because it's the entity that manages the UI view over a defined tree of fragments and views that display information and respond to user interactions.

Android applications are typically composed of one or more subclasses of android.app.Activity. An Activity instance has a very well-defined lifecycle that the system manages through the execution of lifecycle method callbacks, all of which are executed on the main thread.

To keep the application responsive and reactive, and the activity transition smooth, the developer should understand the nature of each Activity lifecycle callback.

The most important callbacks on the Activity lifecycle are as follows:

  • onCreate(): At this state, Activity is not visible, but it is here where all the private Activity resources (views and data) are created. The long and intensive computations should be done asynchronously in order to decrease the time when the users don't get a visual feedback during an Activity transition.
  • onStart(): This is the callback called when the UI is visible, but not able to interact on the screen. Any lag here could make the user angry as any touch event generated at this stage is going to be missed by the system.
  • onResume(): This is the callback called when Activity is going to be in the foreground and at an interactable state.
  • onPause(): This is a callback called when Activity is going to the background and is not visible. Computations should end quickly as the next Activity will not resume until this method ends.
  • onStop(): This is a callback called when Activity is no longer visible, but can be restarted.
  • onDestroy(): This is a callback called when the Activity instance is going to be destroyed in the background. All the resources and references that belong to this instance have to be released.

An Activity instance that is completed should be eligible for garbage collection, but background threads that refer to Activity or part of its view hierarchy can prevent garbage collection and create a memory leak.

Similarly, it is easy to waste CPU cycles (and battery life) by continuing to do background work when the result can never be displayed as Activity is completed.

Finally, the Android platform is free at any time to kill processes that are not the user's current focus. This means that if we have long-running operations to complete, we need some way of letting the system know not to kill our process yet.

All of this complicates the do-not-block–the-main-thread rule as we need to worry about canceling background work in a timely fashion or decoupling it from the Activity lifecycle where appropriate.

Manipulating the user interface

The other Android-specific problem lies not in what you can do with the UI thread, but in what you cannot do.

Note

You cannot manipulate the user interface from any thread other than the main thread.

This is because the user interface toolkit is not thread-safe, that is, accessing it from multiple threads may cause correctness problems. In fact, the user interface toolkit protects itself from potential problems by actively denying access to user interface components from threads other than the one that originally created these components.

If the system detects this, it will instantly notify the application by throwing CalledFromWrongThreadException.

The final challenge then lies in safely synchronizing background threads with the main thread so that the main thread can update the user interface with the results of the background work.

If the developer has access to an Activity instance, the runOnUiThread instance method can be used to update the UI from a background thread.

The method accepts a Runnable object like the one used to create an execution task for a thread:

public final void runOnUiThread (Runnable)

In the following example, we are going to use this facility to publish the result from a synonym search that was processed by a background thread.

To accomplish the goal during the OnCreate activity callback, we will set up onClickListener to run searchTask on a created thread:

// Get the Views references
Button search = (Button) findViewById(R.id.searchBut);
final EditText word = (EditText) findViewById(R.id.wordEt);

// When the User clicks on the search button 
// it searches for a synonym
search.setOnClickListener(new View.OnClickListener() {
    @Override
    public void onClick(View v) {
        // Runnable that Searchs for the synonym and
        // and updates the UI.
        Runnable searchTask = new Runnable() {
            @Override
            public void run() {
                // Retrieves the synonym for the word
                String result = searchSynomim(
                   word.getText().toString());
                // Runs the Runnable SetSynonymResult
                // to publish the result on the UI Thread
                runOnUiThread(new SetSynonymResult(result));
            }
        };
        // Executes the search synonym an independent thread
        Thread thread = new Thread(searchTask);
        Thread.start();
    }
});

When the user clicks on the Search button, we will create a Runnable anonymous class that searches for the word typed in R.id.wordEt EditText and starts the thread to execute Runnable.

When the search completes, we will create an instance of Runnable SetSynonymResult to publish the result back on the synonym TextView over the UI thread:

class SetSynonymResult implements Runnable {
    final String synonym;

    SetSynonymResult(String synonym){
      this.synonym = synonym;
    }
    public void run() {
      TextView tv = (TextView)findViewById(R.id.synonymTv);
      tv.setText(this.synonym);
    }
};

This technique is sometime not the most convenient one, especially when we don't have access to an Activity instance; therefore, in the following chapters, we are going to discuss simpler and cleaner techniques to update the UI from a background computing task.

Service concurrent issues

These are the Android entities that run in the background, which usually perform tasks in the name application that does not require any user interaction.

Service, by default, runs in the main thread of the application process. It does not create its own thread, so if your Service is going to do any blocking operation, such as downloading an image, play a video, or access a network API, the user should design a strategy to offload the time of the work from the main thread into another thread.

As Service could have its own concurrent strategy, it should also take into account that, like Activity, it should update the UI over the main thread, so a strategy to post back the results from the background into the main loop is imperative.

In the Android services domain, the way the service is started distinguishes the nature of Service into the following two groups:

  • Started services: This is the service that is started by startService() that can run definitively even if the component that started it was destroyed. A started service does not interact directly with the component that started it.
  • Bound services: This service exists while at least one Android component is bounded to it by calling bindService(). It provides a two-way (client-server) communication channel for communication between components.

Started services issues

When we implement a started service, any application component is able to start it when it invokes the startService(Intent) method. Once the system receives startService(Intent) and the service is not yet started, the system calls onCreate() and then onStartCommand() with the arguments encapsulated on an Intent object. If the Service already exists, only onStartCommand() is invoked.

The callbacks used by a started service are as follows:

// Called every time a component starts the Service
// The service arguments are passed over the intent
int onStartCommand(Intent intent, int flags, int startId)

// Used to initialize your Service resources
void onCreate()

// Used to release your Service resources
void onDestroy()

In the onStartCommand() callback, once a long computing task is required to handle the service request, a handover to the background threads should be explicitly implemented and coordinated in order to avoid an undesired ANR:

int onStartCommand (Intent intent, int flags, int startId){
    // Hand over the request processing to your
    // background tasks
...
}

When the service is done, and it needs to publish results to the UI, a proper technique to communicate with the main thread should be used.

Bound services issues

A bound service generally used when a strong interaction between an Android component and a service is required.

When the service runs on the same process, the interaction between the Android component (client) and the bound service (server) is always provided by a Binder class returned on onBind(). With the Binder instance on hand, the client has access to the service's public methods, so when any component invokes the bound service public methods, the component should be aware of the following:

  • When a long running operation is expected to take place during the method invocation, the invocation must occur in a separate thread
  • If the method is invoked in a separated thread, and the service wants to update the UI, the service must run the update over the main thread:
    public class MyService extends Service {
     
        // Binder given to clients
        private final IBinder mBinder = new MyBinder();
    
         public class MyBinder extends Binder {
             MyService getService() {
                 // Return this instance of MyService
                 // so clients can call public methods
                 return MyService.this;
            }
        }
        @Override
       
        public IBinder onBind(Intent intent) {
            return mBinder;
        }
    
         /** Method for clients */
        public int myPublicMethod() {
          //
        }
    ...
You have been reading a chapter from
Asynchronous Android Programming - Second Edition
Published in: Jul 2016
Publisher: Packt
ISBN-13: 9781785883248
Register for a free Packt account to unlock a world of extra content!
A free Packt account unlocks extra newsletters, articles, discounted offers, and much more. Start advancing your knowledge today.
Unlock this book and the full library FREE for 7 days
Get unlimited access to 7000+ expert-authored eBooks and videos courses covering every tech area you can think of
Renews at $19.99/month. Cancel anytime
Banner background image