Java Interfaces — Listeners: Activity using AsyncTask in a separate file

An Activity making a direct Intent call using AsyncTask’s onPostExecute(…) while the AsyncTask is at a separate file…

This article is describing a common pattern widely used in Android Development.

There are more cases where this technique applies, for example creating a clickListener for items in a recycler view, where we need to somehow forward click information from the Adapter class to the Activity class… so… keep reading!

The Problem

If AsyncTask class is implemented in a file outside an “Activity”, how can we make the “intent” call from inside the activity, rather than from the AsyncTask class’s “onPostExecute” method?

In a nutshell…

Since our AsyncTask will be a separate java file, then the onPostExecute will be exist on that file, thus outside any Activity.

But if that is the case, how can the original Activity (that called the remote AsyncTask class) update its UI, since the AsyncTask’s onPostExecute lies outside our Activity?

One solution could be to make the AsyncTask an inner class to the Activity, but what if the AsyncTask would execute some code that could be utilized by several different activities. In that case we should have one such inner class implementation of the same AsyncTask on every such activity, which is by far “bad coding”.

So how could we have a remote AsyncTask utilization that notifies the UI of whatever activity called it?

Hmm…

The Solution

We can approach this problem via interfaces.

For this solution, I have two files at GitHub (from a real project) that demonstrate the approach described here. Please open these files from the real project, examine the code and keep up with my walkthrough at this article.

You can find both files at HERE

In short, the solution consists of the following steps:

  1. Declare an interface for TaskCompleteListener in our AsyncTask file
  2. at onPostExecute, we set data to this listener
  3. implement this interface in MainActivity

So as a sample implementation, in our “EndpointsAsyncTask.java” we need to declare an interface like this

On AsyncTask class

At our example, the output of the onPostExecute is a string. So we can create an interface defining a method that takes as param this string, so we forward this string output to whatever activity implements this interface.

// define the interface
public interface TaskCompleteListener {
void onTaskComplete(String result);
}
// define a member variable associated with that interface
private TaskCompleteListener mTaskCompleteListener;

The EndpointsAsyncTask class constructor should now take as parameter one implementation of that interface

public EndpointsAsyncTask(TaskCompleteListener listener) {
mTaskCompleteListener = listener;
}

and then on the onPostExecute we forward the output (“string” in our example) result to whoever implemented that interface (our calling activity).

@Override
protected void onPostExecute(String result) {
if (result != null) {
mTaskCompleteListener.onTaskComplete(result);
}
}

On Activity class

Now given the above, the Activity class that calls the EndpointsAsyncTask should implement the interface via an anonymous inner class implementation.

So we call our AsyncTask, with execute, but on top of that, via our anonymous class implementation of the interface, whatever is produced at the “onPostExecute”, will be forwarded to our “onTaskComplete” implementation.

public void tellJoke() {
new EndpointsAsyncTask(new TaskCompleteListener() {
@Override
public void onTaskComplete(String result) {
Intent intent = new Intent(..., ...);
intent.putExtra(..., ...);
startActivity(intent);
}
).execute(this);
}

Neat right?

The Big Picture

The onPostExecute, forwards a call to whoever implements this method interface, together with the params it received.

The guy that implements the interface, defines the missing method of the interface via an anonymous inner class implementation, so it receives via parameters whatever the onPostExecute forwarded.

Think of it as a listener, it will execute its code only when the onPostExecute forwards a call to the implementor together with the params of the “event”.

Thus now the result of the onPostExecute in the remote class can now be utilized locally at the calling Activity.

MSc Computer Science. — Software engineer and programming instructor. Actively involved in Android Development and Deep Learning.

MSc Computer Science. — Software engineer and programming instructor. Actively involved in Android Development and Deep Learning.