Advertisements

Connecting to the Internet via URLConnection

When apps were knew, there were lots of trivial apps like that made fart noises and displayed virtual zippo lighters. Today the novelty has worn off and apps need to have a little more substance. With very few exceptions, basically all useful apps today require an Internet connection. It is important to understand how to exchange information over the network efficiently, and correctly.

Before you start

Make sure that you have put the Internet permission into your manifest. If you don’t, you’ll get an error like “unknown host” or some other equally uninformative error. To add the internet permission to your app, open the manifest xml and add

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

Basic Internet Connection

The good people at Google have cooked up a pretty simple solution to networking that has been optimized for modern mobile devices. In its most basic form all you need to do is provide it with a URL and it will give you an InputStream containing the result. It looks something like this:

HttpURLConnection conn = (HttpURLConnection) new URL(“http://someurl.com”).openConnection();
InputStream is = conn.getInputStream();

That’s about it! This code will perform a standard GET request at the given url. If this URL points to a web page, the input stream will contain the HTML for that page. If the URL points to a JSON webservice, it will contain JSON.

Generally speaking, the data you receive from the Internet will be in some kind of text format. There are a few exceptions like if you’re making a music streaming app. So you will need to convert that InputStream to a String like this:

BufferedInputStream bis = new BufferedInputStream(in);
ByteArrayOutputStream buf = new ByteArrayOutputStream();
int result = bis.read();
while(result != -1) {
   byte b = (byte)result;
   buf.write(b);
   result = bis.read();
}        
String s = buf.toString();

This will resemble code you’ll find all over the Internet concerning reading data from an InputStream. However, it is not entirely correct. It operates on a few assumptions and is prone to errors. Generally speaking it works, but you may find some special case where it doesn’t. It’s also not very straightforward. After a little searching around, I found two alternatives that I think are better.

The first uses a trick with the Scanner class and some knowledge about the inner representation of the InputStream. All streams start with the ‘\A’ (beginning of input boundary) character. Using this as a delimiter with Scanner will result in a single String containing the full contents of the stream.

String s = new Scanner(is). useDelimiter("\\A").next();

The second is probably more robust, but requires the Commons IO library from Apache (available at http://commons.apache.org/io/). Within this library is a class called IOUtils which can copy the contents of an InputStream to a StringWriter, which can then return a String like this:

StringWriter writer = new StringWriter();
IOUtils.copy(is, writer);
String s = writer.toString();

I cannot say whether Commons IO is any more correct than the Scanner method is, but I figure most people will prefer Scanner because it does not require any external libraries.

Customizing your connection

Now, if all your app did was retrieve webpages then the above code would be all you’d ever need. However, most apps will require more than that. You will need to add headers and query parameters, as well as perform actions other than GET (such as POST, PUT, and DELETE). Now, these customizations are going to be very specific to whatever system you are connecting to, so you will need to learn the details of that system before connecting. I will cover a few basics to get you on your way.

Headers

Http headers specify meta information about the request you are making. Some web services and websites use this information to make decisions about the requests they receive. The most common things you will put into the header of your requests will be some kind of session token, or an API key. These properties could just as easily appear as query parameters. It just depends on the implementation. Headers are represented as key-value pairs and can be set using the setRequestProperty and addRequestProperty methods.

HttpURLConnection conn = (HttpURLConnection) new URL(“http://someurl.com”).openConnection();
conn.setRequestProperty(“key”, “value”);
InputStream is = conn.getInputStream();

The difference between the two is very subtle. setRequestProperty(…) will overwrite any existing values for that key where addRequestProperty(…) will only add the value if the key does not already exist.

Http Method

Setting the Http Method is as simple as calling setRequestMethod(String method) on your connection. For example, if you want to do a POST, you would call setRequestMethod(“POST”). Generally speaking you will only ever set this to GET, POST, PUT, or DELETE. However, technically speaking, you can set this to anything. You may run into a web service that uses custom methods (verbs). By default this is set to “GET”.

Query Parameters

Query parameters contain the data you are sending to the server. This data can be anything you might pass to a method, or may contain some identifier indicating who you are. Essentially they contain any and all data you wish to send from the client (your app) to the server (the web service). How this data is sent changes based on your http method.

If you are doing a GET request, your parameters should be added to the URL following a ‘?’ character. If you are doing a POST, your parameters should be added as the request body, which can be done by converting your parameters to an OutputStream and writing to it to the connection.

Either way, your query string will look like this:

String query = “key1=value1&key2=value2&key3=value3”;

// GET
HttpURLConnection conn = (HttpURLConection) new URL(url + “?” + query).openConnection();
InputStream is = conn.getInputStream();

//POST
HttpURLConnection conn = (HttpURLConection) new
				URL(url).openConnection();
OutputStream os = connection.getOutputStream();
os.write(query.getBytes());
InputStream is = conn.getInputStream();

There is a really good stack overflow question on this that is far more comprehensive found here.

Advanced Connections

As I mentioned before, URLConnection was made to make Internet connections easier to work with. “Easier than what?” you ask? The “old school” way of handling http requests was via classes in the org.apache.http package. These classes assume the developer has a moderately strong understanding of the Http protocol and give you more control over how your requests/responses are handled. If you need some functionality that isn’t present in URLConnection, chances are it’s available in apache. However according to Google, in recent years URLConnection has become more stable and more efficient than apache. I only bring it up to be complete.

Advertisements

One Response to Connecting to the Internet via URLConnection

  1. Pingback: Multitasking in Android « Code Love

Leave a Reply

Please log in using one of these methods to post your comment:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out /  Change )

Google+ photo

You are commenting using your Google+ account. Log Out /  Change )

Twitter picture

You are commenting using your Twitter account. Log Out /  Change )

Facebook photo

You are commenting using your Facebook account. Log Out /  Change )

Connecting to %s

%d bloggers like this: