Sending and Managing Network Requests - nhtechip/android-bootstrap GitHub Wiki

Overview

Network requests are used to retrieve or modify API data or media from a server. This is a very common task in Android development especially for dynamic data-driven clients.

The underlying Java class used for network connections is URLConnection or DefaultHTTPClient. Both of these are lower-level and require completely manual management of parsing the data from the input stream and executing the request asynchronously.

For most common cases, we are better off using a popular third-party library called android-async-http which will handle the entire process of sending and parsing network requests for us in a more robust and easy-to-use way.

Permissions

In order to access the internet, be sure to specify the following permissions in AndroidManifest.xml:

<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
    package="com.example.simplenetworking"
    android:versionCode="1"
    android:versionName="1.0" >
 
   <uses-permission android:name="android.permission.INTERNET" /> 
</manifest>

Sending an HTTP Request

Using android-async-http, sending an HTTP request becomes quite straightforward. We just create an async http client, and then execute a request specifying an anonymous class as a callback:

import com.loopj.android.http.*;

AsyncHttpClient client = new AsyncHttpClient();
RequestParams params = new RequestParams();
params.put("key", "value");
params.put("more", "data");
client.get("http://www.google.com", params, new
    AsyncHttpResponseHandler() {
        @Override
        public void onSuccess(String response) {
            System.out.println(response);
        }

        @Override
        public void onFailure(Throwable e, String s) {
            Log.d("ERROR", e.toString());
        }	
    }
);

This will automatically execute the request asynchronously and fire the onSuccess when the response returns a success code and onFailure if the response does not.

Sending a JSON Request

Similar to sending a regular HTTP request, android-async-http can also be used for sending JSON API requests:

String url = "https://ajax.googleapis.com/ajax/services/search/images";
AsyncHttpClient client = new AsyncHttpClient();
RequestParams params = new RequestParams();
params.put("q", "android");
params.put("rsz", "8");
client.get(url, params, new JsonHttpResponseHandler() {    	    
    @Override
    public void onSuccess(JSONObject response) {
       // Handle resulting parsed JSON response here
    }
});

The request will be sent out with the appropriate parameters passed in the query string and then the response will be parsed as JSON and made available within onSuccess.

Sending an Authenticated API Request

API requests tend to be JSON or XML responses that are sent to a server and then the result needs to be parsed and processed as data models on the client. In addition, many API requests require authentication in order to identify the user making the request. This is typically done with a standard OAuth process for authentication.

We have created a library to make this as simple as possible called android-oauth-handler and a skeleton app to act as a template for a simple rest client called android-rest-client-template. You can see the details of these libraries by checking out their READMEs.

Using these wrappers, you can then send an API request and properly process the response using code like this:

// SomeActivity.java
RestClient client = RestClientApp.getRestClient();
RequestParams params = new RequestParams();
params.put("key", "value");
params.put("more", "data");
client.getHomeTimeline(1, new JsonHttpResponseHandler() {
  public void onSuccess(JSONArray json) {
    // Response is automatically parsed into a JSONArray
    // json.getJSONObject(0).getLong("id");
    // Here we want to process the json data into Java models.
  }

  public void onFailure(Throwable e, JSONObject error) {
    // Handle the failure and alert the user to retry
    Log.e("ERROR", e.toString());
  }
});

Note that as shown above you should also handle failure cases with [JsonHttpResponseHandler](http://loopj.com/android-async-http/doc/com/loopj/android/http/JsonHttpResponseHandler.html#onFailure\(java.lang.Throwable, org.json.JSONObject)) using the onFailure method so your application is robust to "losing internet" and user doesn't become confused with unexpected results.

Displaying Remote Images (The "Easy" Way)

In contrast, using the third party library android-universal-image-loader after proper setup, we can download an image like this:

String imageUri = "http://2.gravatar.com/avatar/858dfac47ab8176458c005414d3f0c36?s=128&d=&r=G";
ImageView ivBasicImage = (ImageView) findViewById(R.id.ivBasicImage);
imageLoader.displayImage(imageUri, ivBasicImage);

The important thing here is to notice just how much cleaner and clearer app develop can be when using third-party high level libraries.

Note that a popular alternative to the universal-image-loader library is called Picasso which serves a similar purpose. After downloading the Picasso jar, we can load an image with:

Picasso.with(context).load(imageUri).into(ivBasicImage);

For more details check out the Picasso documentation.

Displaying Remote Images (The "Hard" Way)

Here's the code to construct an AsyncTask to download a remote image and display the image in an ImageView using just the official Google Android SDK.

package com.example.simplenetworking;

public class MainActivity extends Activity {
	ImageView ivBasicImage;

	@Override
	protected void onCreate(Bundle savedInstanceState) {
		super.onCreate(savedInstanceState);
		setContentView(R.layout.activity_main);
		ivBasicImage = (ImageView) findViewById(R.id.ivBasicImage);
		String url = "http://2.gravatar.com/avatar/858dfac47ab8176458c005414d3f0c36?s=128&d=&r=G";
		// Download image from URL and display within ImageView
		new ImageDownloadTask().execute(url);
	}
        
	// Defines the background task to download and then load the image within the ImageView
	private class ImageDownloadTask extends AsyncTask<String, Void, Bitmap> {
		protected Bitmap doInBackground(String... addresses) {
			// Convert string to URL
			URL url = getUrlFromString(addresses[0]);
			// Get input stream
			InputStream in = getInputStream(url);
			// Decode bitmap
			Bitmap bitmap = decodeBitmap(in);
			// Return bitmap result
			return bitmap;
		}
               
		// Returns the URL object based on the address given
		private URL getUrlFromString(String address) {
			URL url;
			try {
				url = new URL(address);
			} catch (MalformedURLException e1) {
				url = null;
			}
			return url;
		}

		// Returns an input stream by connecting to the given URL
		private InputStream getInputStream(URL url) {
			InputStream in;
			// Open connection
			URLConnection conn;
			try {
				conn = url.openConnection();
				conn.connect();
				in = conn.getInputStream();
			} catch (IOException e) {
				in = null;
			}
			return in;
		}
                
		// Convert the input stream into a Bitmap object using BitmapFactory
		private Bitmap decodeBitmap(InputStream in) {
			Bitmap bitmap;
			try {
				// Turn response into Bitmap
				bitmap = BitmapFactory.decodeStream(in);
				// Close the input stream
				in.close();
			} catch (IOException e) {
				in = null;
				bitmap = null;
			}
			return bitmap;
		}
                
		// Fires after the task is completed, displaying the bitmap into the ImageView
		@Override
		protected void onPostExecute(Bitmap result) {
			// Set bitmap image for the result
			ivBasicImage.setImageBitmap(result);
		}
	}
}

Of course, doing this the "hard" way is not recommended. In most cases, to avoid having to manually manage caching and download management, we are better off creating your own libraries or in most cases utilizing existing third-party libraries.

Note: If you use to above approach to download and display many images within a ListView, you might run into some threading issues that cause buggy loading of images. The blog post Multithreading for Performance offers a solution in which you manage the active remote downloading background tasks to ensure that too many tasks are not being spun up at once.

References

⚠️ **GitHub.com Fallback** ⚠️