abidibo.net

Android development, fetch data from API and execute a callback

android java programming

I love first-class function programming languages (js and python for example), and I use to pass callbacks everywhere, especially when dealing with events or async tasks.

I'm a completely newbie with Java, but I started learning it because I decided time has come to develop android native applications. One of the first functionality I needed and I wanted to master is retrieving information (in json format, in my case) from some sort of API in order to display it in my application.

The equivalent in a modern js application would be making an ajax call to a server endpoint and process the data when fetched. This of course involves the use of callbacks, since data are fetched asynchronously and must be processed when ready.

In Java you can't pass functions as arguments, but it is possible to mimic the same behaviour using interfaces. Here I'll show you how to write a class that can be used to retrieve data, and how to make this class passing the fetched data to a callback method defined in another object consuming the API.

As said, you can't pass a function as an argument in Java, but yes you could pass an object which obligatorily implements a certain interface. In this way you're sure that such object has a certain method, and this method is the one called when the data are fetched.

So let's start from the interface:

/**
 * Interface defining a callable to be used as callback when fetching server data
 */
public interface FetchDataCallbackInterface {
    // method called when server's data get fetched
    public void fetchDataCallback (String result);
}

Now let's see the class that actually performs the request:

import android.os.AsyncTask;

import java.io.BufferedInputStream;
import java.io.BufferedReader;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.net.HttpURLConnection;
import java.net.URL;

/**
 * Allows to fetch string data from a server, given the url and a callable.
 * The callable is an object of a class implementing the FetchDataCallbackInterface
 * which defines the callback method fetchDataCallback
 */
public class FetchData extends AsyncTask {

    HttpURLConnection urlConnection;
    String url;
    FetchDataCallbackInterface callbackInterface;

    /**
     * Constructor
     * @param url
     * @param callbackInterface class which defines the callback method
     */
    public FetchData(String url, FetchDataCallbackInterface callbackInterface) {
        this.url = url;
        this.callbackInterface = callbackInterface;
    }

    @Override
    protected String doInBackground(String... args) {

        StringBuilder result = new StringBuilder();

        try {
            URL url = new URL(this.url);
            urlConnection = (HttpURLConnection) url.openConnection();
            InputStream in = new BufferedInputStream(urlConnection.getInputStream());

            BufferedReader reader = new BufferedReader(new InputStreamReader(in));

            String line;
            while ((line = reader.readLine()) != null) {
                result.append(line);
            }

        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            urlConnection.disconnect();
        }

        return result.toString();
    }

    @Override
    protected void onPostExecute(String result) {
        super.onPostExecute(result);
        // pass the result to the callback function
        this.callbackInterface.fetchDataCallback(result);
    }

}

Ok, now let's see how to use this inside an activity:

import android.content.res.Resources;
import android.os.Bundle;
import android.support.v7.app.AppCompatActivity;
import android.support.v7.widget.Toolbar;
import android.view.Gravity;
import android.view.View;

import org.torinometeo.torinometeo.api.API;
import org.torinometeo.torinometeo.utilities.FetchData;
import org.torinometeo.torinometeo.utilities.FetchDataCallbackInterface;
import org.torinometeo.torinometeo.utilities.Utility;

/**
 * ForecastActivity
 *
 * When created it fetches forecast data from the server once and renders them.
 */
public class ForecastActivity extends AppCompatActivity implements FetchDataCallbackInterface {

    Utility utility = new Utility();

    // data is class member because this activity should behave like a singleton for data
    // this way data are fetched only once and reused by different class instances
    static String data = null;

    @Override
    protected void onCreate(Bundle savedInstanceState) {

        // check internet connection
        if(!utility.checkInternetConnection(this)) {
            utility.showNoConnectionDialog(this);
        }

        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_forecast);
        Toolbar toolbar = (Toolbar) findViewById(R.id.toolbar);
        setTitle(R.string.forecasts);
        setSupportActionBar(toolbar);
        getSupportActionBar().setDisplayHomeAsUpEnabled(true);

        // fetch server data only once
        if(ForecastActivity.data == null) {
            // automatically calls the renderData function
            new FetchData(API.LAST_FORECAST, this).execute();
        }
        else {
            renderData();
        }
    }

    @Override
    public void fetchDataCallback(String result) {
        data = result;
        renderData();
    }

    public void renderData() {
        // do something with your data here
    }

}

As you can see, this class implements the above defined interface, so it is mandatory to implement the interface's method, and we're sure that any object of this type will have a method called fetchDataCallback.

The interesting part starts at line 42. I used a static member to keep the data because I don't want to fetch them every time the activity is created. This specific kind of data don't vary in hours so it's better to have some sort of cache. If data were not retrieved yet, then FetchData is instantiated and executed, otherwise the data are already present and can be rendered.

When FetchData is instantiated we pass the API url and a reference to the current activity object. This object implements the fetchDataCallback method which in this way acts as our callback.

When FetchData is executed and the data are fetched, the method defined by the interface is called, so the fetchDataCallback method of our Activity object is executed. Here we can manipulate our data.

That's it, nothing extraordinary, but I'm starting my walk through the world of Java so I have to proceed step by step.

Bye!

Subscribe to abidibo.net!

If you want to stay up to date with new contents published on this blog, then just enter your email address, and you will receive blog updates! You can set you preferences and decide to receive emails only when articles are posted regarding a precise topic.

I promise, you'll never receive spam or advertising of any kind from this subscription, just content updates.

Subscribe to this blog

Comments are welcome!

blog comments powered by Disqus

Your Smartwatch Loves Tasker!

Your Smartwatch Loves Tasker!

Now available for purchase!

Featured