Calling Web Services in Background Using MAF 2.1

Introduction

Responsiveness of mobile applications is absolutely critical for user acceptance. This survey shows that the most important reason for users to discard an app after first use is the performance. When building enterprise mobile apps, the web service calls made to back-end services are often a bottleneck in achieving acceptable levels of performance. Moving these calls to a background thread, in combination with on-device data caching using the SQLite database is often an efficient and effective way of addressing these performance challenges. This article explains how you can easily execute more expensive tasks like these web service calls in the background using Oracle MAF 2.1 and at the same time provide the user with a visual indicator that a data operation is being executed in the background.

Main Article

When starting to implement web service calls and associated processing logic in the background, you need to realize that the user can continue to use the application, tap and navigate around, while triggering additional data actions, and as a result fire multiple concurrent background tasks for potentially more than one feature. Is that a problem? Yes, most likely it will cause problems if you have multiple background threads processing data simultaneously:

  • The sequence in which the background tasks are triggered might be important, for example when the result of one REST or SOAP call needs to be used, or is assumed to be processed before the next web service call takes place. With multiple concurrent background threads, this sequence cannot be guaranteed.
  • The on-device SQLite database is a single user database. It can cause errors or unexpected results when multiple background threads are writing data to the same SQLite database.

So, to guarantee correct sequencing of web service calls and avoid concurrency issues with SQLite database, it is best to execute all background tasks in one and the same thread using a queueing mechanism. You might be puzzled how to build such functionality, but the good news is that this is extremely simple in MAF 2.1 because we can now leverage Java JDK 1.8.

Let’s start with the simplest imaginable version of our BackgroundTaskExecutor class:

public class BackgroundTaskExecutor {

    private static BackgroundTaskExecutor instance;
    ExecutorService executor = Executors.newSingleThreadExecutor();

    public BackgroundTaskExecutor() {
        super();
    }

    public static synchronized BackgroundTaskExecutor getInstance() {
        if (instance == null) {
            instance = new BackgroundTaskExecutor();
        }
        return instance;
    }

    public void execute(Runnable task) {
        executor.submit(task);
    }
}

In this class we are leveraging some classes from the java.util.concurrent package that is available in Compact2 Profile of JDK 1.8 that is used in MAF 2.1. Most notably is the Executors class that contains a convenience method that creates a single tread pool with built-in queueing mechanism, exactly what we need!

To use this class, we need to call the execute method, passing in an instance of Runnable. Using the new Lambda expressions of JDK 1.8 it is easy to create this Runnable method argument. Here is a code snippet from the demo application that comes with this post that loads some departments in the background:

public class DepartmentService {

    List departments = new ArrayList();
    private transient ProviderChangeSupport providerChangeSupport = new ProviderChangeSupport(this);

    public List getDepartments() {
        return departments;
    }

    public void loadDepartments() {
        BackgroundTaskExecutor.getInstance().execute(
         () -> { 
           // mimic slow SOAP or REST call by waiting for 3 seconds
            try {
                Thread.sleep(3000);
            } catch (InterruptedException e) {
            } 
             departments.add(new Department("1","Marketing"));
             departments.add(new Department("2","Sales"));
             departments.add(new Department("3","Support"));
             providerChangeSupport.fireProviderRefresh("departments");
             AdfmfJavaUtilities.flushDataChangeEvent();
         });
    }

To further enhance the user experience, it would be nice to provide a visual indicator that tells the user that some data operation is taking place in the background. To implement this, we need to enhance our BackgoundTaskExecutor class and check whether the last task is completed.Here is the code we need to add to get a boolean EL expression that returns true when there is some task running in the background:

    private boolean running = false;
    private Future<?> lastFuture = null;

    protected void setRunning(boolean running) {
        AdfmfJavaUtilities.setELValue("#{applicationScope.bgtask_running}", running);
        AdfmfJavaUtilities.flushDataChangeEvent();
    }

    protected void updateStatus() {
        if (!running) {
            Thread t = new Thread(
            () -> {
                if (!lastFuture.isDone()) {
                    setRunning(true);
                }
                while (!lastFuture.isDone()) {
                    try {
                        // Check every 0,1 second if task is completed
                        Thread.sleep(100);
                    } catch (InterruptedException e) {
                    }
                }
                setRunning(false);
                AdfmfJavaUtilities.flushDataChangeEvent();
            });
            t.start();
        }
    }

    public synchronized void execute(Runnable task) {
        lastFuture = executor.submit(task);
        updateStatus();
    }

We have defined two additional member variables, one to keep track of the current running state, and one that holds the so-called Future of the last submitted task. A Future is an object that is returned when submitting a task, which can be used to track the progress of the task by calling the isDone() method.So, to tie it together, we update the lastFuture variable when submitting a new task, and we call the updateStatus method to ensure the UI gets notified of a running background task. The updateStatus method spawns a separate threat that runs until the task is completed. Every 0,1 second, the status of the last submitted task is checked and if it is completed the running variable of the class is set to false as well as the applicationScope variable “bgtask_running”. If a task is submitted while another one is still running, then the updateStatus method will just do nothing, the existing background thread will now automatically check this last submitted task since we updated the lastFuture variable.

With this code in place, we can now easily show some spinning icon in the user interface:

<amx:image id="i1" source="/images/reloading.gif" rendered="#{applicationScope.bgtask_running}"/>

You can download the sample application that comes with this blog post and test the functionality yourself.

Demo

The demo consists of a page with a list of departments. The list can be incrementally loaded using two buttons. As longs as at least one of the two loading tasks is running a spinning refresh icon is shown in the upper-right corner.

This article only discussed the overall technique of running tasks in the background. If you are looking for a more comprehensive solution that includes code to process REST or SOAP calls and cache results in a local SQLite database, you should check out the A-Team Mobile Persistence Accelerator. This accelerator comes as a free JDeveloper extension and contains advanced wizards and generic runtime code, that allows you to create a persistence layer that supports offline reads and writes and with data and web service operations (optionally) executed in the background. All this functionality comes out-of-the-box and requires no Java coding from your side.

Add Your Comment