In this example, we download an image and text from the web.
Let's preview the whole Java code first, HttpURLConncecitonA.java:
package com.bogotobogo.httpconnecta; import java.io.IOException; import java.io.InputStream; import java.io.InputStreamReader; import java.net.HttpURLConnection; import java.net.MalformedURLException; import java.net.URL; import java.net.URLConnection; import android.app.Activity; import android.app.ProgressDialog; import android.graphics.Bitmap; import android.graphics.BitmapFactory; import android.os.Bundle; import android.os.Handler; import android.os.Message; import android.view.View; import android.view.View.OnClickListener; import android.widget.Button; import android.widget.ImageView; import android.widget.TextView; public class HttpURLConnectionA extends Activity { private ProgressDialog progressDialog; private Bitmap bitmap = null; private String text = null; /** Called when the activity is first created. */ @Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.main); Button imageBtn = (Button)findViewById(R.id.Button01); Button textBtn = (Button)findViewById(R.id.Button02); imageBtn.setOnClickListener( new OnClickListener() { @Override public void onClick(View v) { downloadImage("http://www.bogotobogo.com/images/smalltiger.gif"); } }); textBtn.setOnClickListener(new OnClickListener() { @Override public void onClick(View v) { downloadText("http://www.bogotobogo.com/android.html"); } }); } private void downloadImage(String urlStr) { progressDialog = ProgressDialog.show(this, "", "Downloading Image from " + urlStr); final String url = urlStr; new Thread() { public void run() { InputStream in = null; Message msg = Message.obtain(); msg.what = 1; try { in = openHttpConnection(url); bitmap = BitmapFactory.decodeStream(in); Bundle b = new Bundle(); b.putParcelable("bitmap", bitmap); msg.setData(b); in.close(); } catch (IOException e1) { e1.printStackTrace(); } messageHandler.sendMessage(msg); } }.start(); } private void downloadText(String urlStr) { progressDialog = ProgressDialog.show(this, "", "Download Text from " + urlStr); final String url = urlStr; new Thread () { public void run() { int BUFFER_SIZE = 2000; InputStream in = null; Message msg = Message.obtain(); msg.what=2; try { in = openHttpConnection(url); InputStreamReader isr = new InputStreamReader(in); int charRead; text = ""; char[] inputBuffer = new char[BUFFER_SIZE]; while ((charRead = isr.read(inputBuffer))>0) { String readString = String.copyValueOf(inputBuffer, 0, charRead); text += readString; inputBuffer = new char[BUFFER_SIZE]; } Bundle b = new Bundle(); b.putString("text", text); msg.setData(b); in.close(); }catch (IOException e2) { e2.printStackTrace(); } messageHandler.sendMessage(msg); } }.start(); } private InputStream openHttpConnection(String urlStr) { InputStream in = null; int resCode = -1; try { URL url = new URL(urlStr); URLConnection urlConn = url.openConnection(); if (!(urlConn instanceof HttpURLConnection)) { throw new IOException ("URL is not an Http URL"); } HttpURLConnection httpConn = (HttpURLConnection)urlConn; httpConn.setAllowUserInteraction(false); httpConn.setInstanceFollowRedirects(true); httpConn.setRequestMethod("GET"); httpConn.connect(); resCode = httpConn.getResponseCode(); if (resCode == HttpURLConnection.HTTP_OK) { in = httpConn.getInputStream(); } } catch (MalformedURLException e) { e.printStackTrace(); } catch (IOException e) { e.printStackTrace(); } return in; } private Handler messageHandler = new Handler() { public void handleMessage(Message msg) { super.handleMessage(msg); switch (msg.what) { case 1: ImageView img = (ImageView) findViewById(R.id.imageview01); img.setImageBitmap((Bitmap)(msg.getData().getParcelable("bitmap"))); break; case 2: TextView text = (TextView) findViewById(R.id.textview01); text.setText(msg.getData().getString("text")); break; } progressDialog.dismiss(); } }; }
Since retrieving data from the internet can be a time consuming, we use a separate thread to get the image file. We should not use UI/main thread doing this kind of task as we discussed in the 22. Threads.
How do we get a connection when we press the Download button?
At the click of a button, Download Image, we first open an HTTP connection to the server and then request for the image. Here is the our method, openHttpConnection(String urlStr), just for that task. Basically it is our utility code for retrieving image/text from the internet.
private InputStream openHttpConnection(String urlStr) { InputStream in = null; int resCode = -1; try { URL url = new URL(urlStr); URLConnection urlConn = url.openConnection(); if (!(urlConn instanceof HttpURLConnection)) { throw new IOException ("URL is not an Http URL"); } HttpURLConnection httpConn = (HttpURLConnection)urlConn; httpConn.setAllowUserInteraction(false); httpConn.setInstanceFollowRedirects(true); httpConn.setRequestMethod("GET"); httpConn.connect(); resCode = httpConn.getResponseCode(); if (resCode == HttpURLConnection.HTTP_OK) { in = httpConn.getInputStream(); } } catch (MalformedURLException e) { e.printStackTrace(); } catch (IOException e) { e.printStackTrace(); } return in; }
Here, we open a URLConnection
URLConnection urlConn = url.openConnection();
Then, checks if it is an instance of HttpURLConnection
if (!(urlConn instanceof HttpURLConnection)) { throw new IOException ("URL is not an Http URL"); }
then, sets the parameters required
HttpURLConnection httpConn = (HttpURLConnection)urlConn; httpConn.setAllowUserInteraction(false); httpConn.setInstanceFollowRedirects(true); httpConn.setRequestMethod("GET");
and made the connection by calling the connect() method.
httpConn.connect();
Then, we check if the response code is OK and I get a handle to the input stream.
resCode = httpConn.getResponseCode(); if (resCode == HttpURLConnection.HTTP_OK) { in = httpConn.getInputStream(); }
Now, we know how we are connected to the internet.
And we get input stream through the connection using a hard coded URL of our image.
Let's step back a little bit, and check how we feed that URL at the click of Download Image button.
Button imageBtn = (Button)findViewById(R.id.Button01); ... imageBtn.setOnClickListener( new OnClickListener() { @Override public void onClick(View v) { downloadImage("http://www.bogotobogo.com/images/smalltiger.gif"); } });
So, actually downloading an image is done through our method, downloadImage(String url).
private void downloadImage(String urlStr) { progressDialog = ProgressDialog.show(this, "", "Downloading Image from " + urlStr); final String url = urlStr; new Thread() { public void run() { InputStream in = null; Message msg = Message.obtain(); msg.what = 1; try { in = openHttpConnection(url); bitmap = BitmapFactory.decodeStream(in); Bundle b = new Bundle(); b.putParcelable("bitmap", bitmap); msg.setData(b); in.close(); } catch (IOException e1) { e1.printStackTrace(); } messageHandler.sendMessage(msg); } }.start(); }
If we are not getting the image in a separate thread, we only need the three lines of code.
in = openHttpConnection(url); bitmap = BitmapFactory.decodeStream(in); ...... in.close();
Open a connection, get the bitmap and close the connection. However, since this is a typical task with unpredictable response time, it should be done in a separate thread of its own.
So, before we start a new thread, we let the UI thread to show a ProgressDialog for our impatient user.
progressDialog = ProgressDialog.show(this, "", "Downloading Image from " + urlStr);
Then, we start a new thread. we make the URL string accessible within the new thread by making it a final variable. Since message is an object that we can use for communication between threads, we create a Message object in the thread. Then, we set the message number to 1, so that we can use it later.
Message msg = Message.obtain(); msg.what = 1;
Then, we bundle our bitmap already put into a Bundle object that can be sent back in the Message object.
Bundle b = new Bundle(); b.putParcelable("bitmap", bitmap); msg.setData(b);
Once we close the input stream as in:
in.close();
the thread has completed the job. So, we notify the main / UI thread through this method and also pass on the Message object:
messageHandler.sendMessage(msg);
Now we got the image through a Message in a separate thread.
But, how do we retrieve the image from the Message object in the main thread?
As soon as the child thread notifies, the method called back in the main thread is the handleMessage(msg) method.
It is in handleMessage(msg) method that we retrieve the bitmap and set it to the ImageView in the UI.
private Handler messageHandler = new Handler() { public void handleMessage(Message msg) { super.handleMessage(msg); switch (msg.what) { case 1: ImageView img = (ImageView) findViewById(R.id.imageview01); img.setImageBitmap((Bitmap)(msg.getData().getParcelable("bitmap"))); break; case 2: TextView text = (TextView) findViewById(R.id.textview01); text.setText(msg.getData().getString("text")); break; } progressDialog.dismiss(); } };
Within this method, first we check the msg.what variable to see what the type of message we're expecting is. If it is 1, which we had set in downloadImage(..) method, then, we do the required things to get a handle to the ImageView object and then give the bitmap to it.
How do we get the data from the msg object?
Through getData(). Then we use the key bitmap to retrieve the bitmap and cast it to Bitmap before setting it to the ImageView.
Finally, we dismiss the progress dialog.
Our layout file, /res/layout/main.xml:
<?xml version="1.0" encoding="utf-8"?> <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" android:orientation="vertical" android:layout_width="fill_parent" android:layout_height="fill_parent" android:scrollbars="vertical"> <Button android:id="@+id/Button01" android:text="@string/button01" android:layout_height="wrap_content" android:layout_width="wrap_content"> </Button> <Button android:id="@+id/Button02" android:layout_height="wrap_content" android:text="@string/button02" android:layout_width="wrap_content"> </Button> <ImageView android:id="@+id/imageview01" android:layout_width="wrap_content" android:layout_height="wrap_content" android:cropToPadding="true" > </ImageView> <TextView android:id="@+id/textview01" android:layout_width="fill_parent" android:layout_height="wrap_content" /> </LinearLayout>
AndroidManifest.xml:
<?xml version="1.0" encoding="utf-8"?> <manifest xmlns:android="http://schemas.android.com/apk/res/android" android:versionCode="1" android:versionName="1.0" package="com.bogotobogo.httpconnecta"> <application android:icon="@drawable/icon" android:label="@string/app_name"> <activity android:name=".HttpURLConnectionA" android:label="@string/app_name"> <intent-filter> <action android:name="android.intent.action.MAIN" /> <category android:name="android.intent.category.LAUNCHER" /> </intent-filter> </activity> </application> <uses-sdk android:minSdkVersion="7" /> <uses-permission android:name="android.permission.INTERNET"> </uses-permission> </manifest>
Files used in this HTTP Connection example A, HttpURLConnectionA.zip