Asynchronous calls in and out of scope an Activity in Android

- Andrés Cruz

En español

When you want to make an asynchronous call in HTML whose request is not "lost" in time, it is very easy through AJAX; if we use jQuery it is even easier due to its syntax and few lines; in Android although it is really simple, things change and it is not so direct; The first thing that occurs to us is to make a request through a threat within the scope of an Activity in Android as follows:

public class MyActivity extends Activity {
...
new Thread(new Runnable() {
    public void run() {
        //Aquí ejecutamos nuestras tareas costosas
    }
}).start();
...

Problems with the above asynchronous call...

It may not be entirely advisable to use the above code within the scope of an Android Activity or Fragment depending on the expected output; that is, suppose we use a threat from an Activity in Android with the aim of making a request to obtain data from a Web Server via HTTP to finally display them in some way (for example a list or table).

Depending on the volume of data to receive and the connection you have at that time, the query time varies. Let's assume that it takes me about 3 seconds in total to make the request; Now, what do you think happens when the user rotates the screen before 3 seconds, for example at 1.5 seconds:

Cambio de orientación pantalla

The request is "lost" and given the Life Cycle of an Activity in Android, the onCreate method would be called again and with this our HTTP request of about 3 seconds.

In addition to the case presented above, it is also possible that the user navigates to another Android Activity during the time the request is made (in our example 3 seconds) and the connection will be lost again.

This is due to the fact that an asynchronous method (in our case a threat) is defined within the scope of an Android Activity and therefore it is forced to abide by the Android Activity Life Cycle.

What can we do to avoid losing asynchronous calls?

Declare our asynchronous thread or process in a separate class or outside the scope of the Android Activity or Fragment; but this again brings the inconvenience that when rotating the screen or moving to another Android Activity the request is made through a new instance; although we can avoid this case by creating a single instance class (Singleton Design Pattern) and in this way it is avoided creating new instances throughout the application, but this will be the subject of another post; to create an asynchronous class we can use the class provided by the Android API called AsyncTask:

public class MyAsyncTask extends AsyncTask<Void, Void, String> {

	public AsyncResponse delegate = NULL;

	@Override
	public String doInBackground(Void... params) {
		return NULL;
	}

	@Override
	public void onPostExecute(String result) {
		delegate.processFinish(result);
	}

The methods doInBackground(Void... params) and onPostExecute(String result) are asynchronous where onPostExecute(String result) is executed after doInBackground(Void... params); You can see the total of the methods in the following link AsyncTask API Android.

In addition, the onPostExecute(String result) method of the MyAsyncTask class calls the method called processFinish(result) of the AsyncResponse class whose definition we will see below.

What if we want to perform some task in the Android Activity after the asynchronous process returns the data?

For that, the AsyncResponse Interface is used within the previous class called AsyncResponse that contains the following code:

public interface AsyncResponse {
	void processFinish(String output);
}

To use the asynchronous process or task from an Android Activity or Fragment we use the following code:

public class MyFragment extends Fragment implements
		AsyncResponse {

...
myAsyncTask = new MyAsyncTask();
…

	public void processFinish(String output) {
//El método processFinish() es invocado cuando la clase 
//asíncrona llamada MyAsyncTask ejecuta el método onPostExecute(result) method.
	}
}

The AsyncTask class is perfect for handling short-lived (few seconds) background processes.

  • We implement the AsyncResponse interface in our Android Fragment or Activity.
  • The method called processFinish(String output) is used to return any data (for example in JSON format) to our Activity or Android Fragment and perform some operation from the main thread of our application.

The processFinish(String output) method of our Android Activity or Fragment is called when the asynchronous class called MyAsyncTask executes the onPostExecute(result) method.

Uses of the AsyncTask class

The scheme of the previous code, in addition to being able to adapt it to make HTTP requests, can also be adapted to carry out other types of work, such as carrying out an action after a certain amount of time (for example, 5 seconds).

Why would you be interested in carrying out actions based on a time?

As an Android developer you are surely also a user of this platform; You will have noticed the typical "Undo Action" that Google implements in its applications, as in the case of gmail:

Deshacer en Gmail

The action triggered by clicking on the "Undo" button on this panel is to undo the removal of an email a few moments ago.

Simulating undo by asynchronous call

We could use the scheme outlined above to simulate this action:

  1. Some of the listed items are selected and removed (although internally the item is simply hidden -it is NOT removed from the Database-).

When performing a task that requires the undo function, the class called MyAsyncTask could be invoked, which must implement a thread whose only function would be to sleep for a certain time (5 seconds) that must coincide with the time that the panel is displayed on the screen.

If in that period the user has not reverted his action, then the record selected by the user is deleted; Otherwise, the initially hidden list item is shown again.

  1. The implementation of the scheme raised above will be discussed in another installment on Android.
Andrés Cruz

Desarrollo con Laravel, Django, Flask, CodeIgniter, HTML5, CSS3, MySQL, JavaScript, Vue, Android, iOS, Flutter

Andrés Cruz en Udemy