Android HTTP requests made easy

Posted by

If you’ve ever had to make an HTTP network request in Android, you know what a pain it can be. Making Android HTTP requests usually involves writing a lot of boilerplate code. You could make things a bit easier by creating some custom classes, but it can still be tedious.

In this tutorial I will show you how to make network requests using two different methods. The first method involves creating custom classes, which will aid in code reusability. The second method involves adding a library called the Android Asynchronous Http Client by loopj. This library will greatly reduce the amount of code you will need to write.

In addition, we will be making a network request to the BitcoinAverage API which returns a JSON string. You will learn how to handle the JSON string, both with and without the use of the Android Asynchronous Http Client library.

This tutorial is for those who:

  • are comfortable with the Android development environment;
  • want to learn an easier way to make HTTP requests in Android.

Note: you should also be comfortable with Java and how Object-Orientation works in Java.

 

Adding permissions

This step is relevant to both methods. Navigate to your AndroidManifiest.xml file and add the following permission before the <application> tag:

<uses-permission android:name="android.permission.INTERNET" />

 

Method 1: Creating custom classes

The first class we will be creating is called the RequestPackage class. This class will accept three important values when making HTTP requests. First, it will receive the URL. Next, it will receive the request method (POST or GET). Last, it will receive any values that the server might need (e.g. product_id). The request package will then be sent to the HttpManager class that we will create later.

Create a class called RequestPackage and add the following code to the class:

public class RequestPackage {
    private String url;
    private String method = "GET"; //method is set to GET by default
    private Map<String, String> params = new HashMap<>();//This will hold any values
                                                         //that the server may require
                                                         // e.g. product_id
    public String getUrl() {
        return url;
    }
    
    public void setUrl(String url) {
        this.url = url;
    }    
    
    public String getMethod() {
        return method;
    }    
    
    public void setMethod(String method) {
        this.method = method;
    }    
    
    public Map<String, String> getParams() {
        return params;
    }    
    
    public void setParams(Map<String, String> params) {
        this.params = params;
    }    
    
    public void setParam(String key, String value) {
        params.put(key, value); //adds a single value to the params member variable
    }     
     
    //The method below is only called if the request method has been set to GET
    //GET requests sends data in the url and it has to be encoded correctly in order 
    //for the server to understand the request. This method encodes the data in the 
    //params variable so that the server can understand the request    
    
    public String getEncodedParams() {
        StringBuilder sb = new StringBuilder();
        for (String key : params.keySet()) {
            String value = null;
            try {
                value = URLEncoder.encode(params.get(key), "UTF-8");
            } catch (UnsupportedEncodingException e) {
                e.printStackTrace();
            }
    
            if (sb.length() > 0) {
                sb.append("&");
            }
            sb.append(key + "=" + value);
        }
        return sb.toString();
    }
}

 

HttpManager

Next, we will create the HttpManager class. As mentioned earlier, the HttpManager receives the RequestPackage that we created in the previous section. The HttpManager is responsible for making the actual request and receiving the response from the server.

Create a class called HttpManager and add the following code to it:

public class HttpManager {

    public static String getData(RequestPackage requestPackage) {
    
        BufferedReader reader = null;
        String uri = requestPackage.getUrl();
    
        if (requestPackage.getMethod().equals("GET")) {
            uri += "?" + requestPackage.getEncodedParams();
            //As mentioned before, this only executes if the request method has been
            //set to GET
        }
    
        try {
            URL url = new URL(uri);
            HttpURLConnection con = (HttpURLConnection) url.openConnection();
            con.setRequestMethod(requestPackage.getMethod());
    
            if (requestPackage.getMethod().equals("POST")) {
                con.setDoOutput(true);
                OutputStreamWriter writer = 
                             new OutputStreamWriter(con.getOutputStream());
                writer.write(requestPackage.getEncodedParams());
                writer.flush();
            }
    
            StringBuilder sb = new StringBuilder();
            reader = new BufferedReader(new InputStreamReader(con.getInputStream()));
    
            String line;
    
            while ((line = reader.readLine()) != null) {
                sb.append(line + "\n");
            }
    
            return sb.toString();
    
        } catch (Exception e) {
            e.printStackTrace();
            return null;
        } finally {
            if (reader != null) {
                try {
                    reader.close();
                } catch (IOException e) {
                    e.printStackTrace();
                    return null;
               }
            }
        }
    }
}

 

Putting it all together

Finally, we can use the code we just implemented. Here we will be putting everything together within the MainActivity. We will have to create a private class within the MainActivity and we will call it Downloader.

The Downloader class is an AsyncTask, which is required when making network requests in Android. If you try to make network requests outside an AsyncTask, your UI will freeze until it gets the HTTP response from the server.

Create an activity called MainActivity and add the following code:

public class MainActivity extends AppCompatActivity {

    private TextView mPriceTextView;
    private String BASE_URL = "https://apiv2.bitcoinaverage.com/indices/global/ticker/BTC";
    
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
    
        setContentView(R.layout.activity_main);
    
        mPriceTextView = (TextView) findViewById(R.id.priceLabel);
        Button btnUSD = (Button) findViewById(R.id.btnUSD);
        Button btnZAR = (Button) findViewById(R.id.btnZAR);
        Button btnAUD = (Button) findViewById(R.id.btnAUD);
    
        //When clicking on this button, the bitcoin price is displayed in the 
        //mPriceTextView in USD
        btnUSD.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View view) {
                requestData(BASE_URL + "USD");
            }
        });
    
        //When clicking on this button, the bitcoin price is displayed in the 
       //mPriceTextView in ZAR
        btnZAR.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View view) {
                requestData(BASE_URL + "ZAR");
            }
        });
    
        //When clicking on this button, the bitcoin price is displayed in the 
        //mPriceTextView in AUD
        btnAUD.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View view) {
                requestData(BASE_URL + "AUD");
            }
        });
    }
    
    private void requestData(String url) {
        RequestPackage requestPackage = new RequestPackage();
        requestPackage.setMethod("GET");
        requestPackage.setUrl(url);
    
        Downloader downloader = new Downloader(); //Instantiation of the Async task 
                                                 //that’s defined below
    
        downloader.execute(requestPackage);
    }
    
    private class Downloader extends AsyncTask<RequestPackage, String, String> {
        @Override
        protected String doInBackground(RequestPackage... params) {
            return HttpManager.getData(params[0])
        }
    
        //The String that is returned in the doInBackground() method is sent to the
        // onPostExecute() method below. The String should contain JSON data.
        @Override
        protected void onPostExecute(String result) {
            try {
                //We need to convert the string in result to a JSONObject
                JSONObject jsonObject = new JSONObject(result);
    
                //The “ask” value below is a field in the JSON Object that was 
                //retrieved from the BitcoinAverage API. It contains the current 
                //bitcoin price
                String price = jsonObject.getString("ask");
         
               //Now we can use the value in the mPriceTextView
               mPriceTextView.setText(price);
            } catch (JSONException e) {
                e.printStackTrace();
            }
        }
    }
}

 

And we are done. The amount of code we needed to write in order to get those three small pieces of information is a lot. It gets even worse if you want to use something like a RecyclerView. That would involve creating an adapter, which would significantly increase the amount of code we need to write.

In the next section, I will show you how to do the same thing by making use of the Android Asynchronous Http Client.

 

Method 2: Android Asynchronous HTTP Client

Navigate to the app/build.gradle file and enter the code below in the dependencies section:

dependencies {
    compile 'com.loopj.android:android-async-http:1.4.9'
}

Android Studio will ask if you would like to sync your project. You should do this and the dependencies will be downloaded.

 

Creating the MainActivity

Next, you will need to add the code below to the MainActivity:

public class MainActivity extends AppCompatActivity {

    private TextView mPriceTextView;
    
    private String BASE_URL = "https://apiv2.bitcoinaverage.com/indices/global/ticker/BTC";
       
    @Override 
    protected void onCreate(Bundle savedInstanceState) {   
        super.onCreate(savedInstanceState);
    
        setContentView(R.layout.activity_main);
    
        mPriceTextView = (TextView) findViewById(R.id.priceLabel);        
        Button btnUSD = (Button) findViewById(R.id.btnUSD);    
        Button btnZAR = (Button) findViewById(R.id.btnZAR);    
        Button btnAUD = (Button) findViewById(R.id.btnAUD);    
    
        //When clicking on this button, the bitcoin price is displayed in the 
        //mPriceTextView in USD        
        btnUSD.setOnClickListener(new View.OnClickListener() {    
            @Override
            public void onClick(View view) {    
                requestData(BASE_URL + "USD");    
            }    
        });        
    
        //When clicking on this button, the bitcoin price is displayed in the 
        //mPriceTextView in ZAR    
        btnZAR.setOnClickListener(new View.OnClickListener() {   
            @Override    
            public void onClick(View view) {    
                requestData(BASE_URL + "ZAR");    
            }    
        });        
    
        //When clicking on this button, the bitcoin price is displayed in the 
        //mPriceTextView in AUD    
        btnAUD.setOnClickListener(new View.OnClickListener() {    
            @Override    
            public void onClick(View view) {    
                requestData(BASE_URL + "AUD");
            }    
        });    
    }        
    
    private void requestData(String url) { 
        //Everything below is part of the Android Asynchronous HTTP Client        
    
        AsyncHttpClient client = new AsyncHttpClient();
    
        client.get(url, new JsonHttpResponseHandler() {            
            @Override    
            public void onSuccess(int statusCode, Header[] headers, 
                                  JSONObject response) {    
                // called when response HTTP status is "200 OK"   
                Log.d("Bitcoin", "JSON: " + response.toString());    
    
                try {
    
                   //The “ask” value below is a field in the JSON Object that was 
                   //retrieved from the BitcoinAverage API. It contains the current 
                   //bitcoin price 
   
                    String price = response.getString("ask");        
    
                    //Now we can use the value in the mPriceTextView
    
                    mPriceTextView.setText(price);
    
                } catch (Exception e) {
    
                    Log.e("Bitcoin", e.toString());
    
                }
    
            }
           
            @Override    
            public void onFailure(int statusCode, Header[] headers, Throwable e, 
                                  JSONObject response) {
    
                // called when response HTTP status is "4XX" (eg. 401, 403, 404)
    
                Log.d("Bitcoin", "Request fail! Status code: " + statusCode);
                Log.d("Bitcoin", "Fail response: " + response);
                Log.e("ERROR", e.toString());
    
                Toast.makeText(MainActivity.this, "Request Failed",
                                Toast.LENGTH_SHORT).show();    
            }    
        });        
    }
}

Run your app and, voila, you’re done. 

Conclusion

Well done! You have completed this tutorial. As you can see, the amount of code needed when working with the Android Asynchronous Http Client is far less than making HTTP requests using no library.

You now have a choice to make: do you prefer method 1 or method 2?

To find out more about the Android Asynchronous Http Client, please visit: http://loopj.com/android-async-http/

To view and/or clone a similar project to the one in this tutorial – that also uses the Android Asynchronous Http Client – please visit: https://github.com/londonappbrewery/bitcoin-ticker-android-citispy

To find out more about the BitcoinAverage API, please visit: https://bitcoinaverage.com/

 

Find out more about our Certified Mobile Developer Bootcamp. You will cover the following modules: Java Programming Essentials, Introduction to Mobile Development and Advanced Mobile Developer.


This article was contributed by Yusuf Isaacs.

Editor’s note: This was post was originally published November 14th, 2017 and has been updated February 18th, 2019. 

Leave a Reply

Your email address will not be published. Required fields are marked *