AndroidHttpClientを用いたデータ取得

Androidで、HTTPを用いてWebサーバ上のデータを取得する手段はいくつかあるようですが、今回はAndroidHttpClientを使って、HTTPサーバから取得した文字列をTextView上に表示するというサンプルを作ってみました。

主なポイントは以下の2点です。

  • AndroidManifest.xmlandroid.permission.INTERNETのパーミッションが必要がある。
  • AndroidHttpClientはUIスレッドで動かすことはできないので、別途スレッドを作って動かす必要がある。

スレッドを作る手段も複数ありますが、今回は比較的お手軽と思われるAsyncTaskを使いました。

また、AndroidHttpClientではHTTPレスポンスボディはInputStreamとして得られますが、これをStringに変換する処理は若干面倒なので、今回はApache Commons IOに含まれるIOUtilsを利用しました。

テスト環境は以下の通りです。

AndroidManifest.xmlの記述

ここは特に問題ないと思いますが、AndroidManifest.xml中のmanifest要素の子要素としてINTERNETパーミッションを追加します。

<manifest xmlns:android="http://schemas.android.com/apk/res/android" ... >
    <uses-sdk
        android:minSdkVersion="9"
        android:targetSdkVersion="15" />
    <uses-permission android:name="android.permission.INTERNET"/>

レイアウトの記述

本題ではありませんが、一応今回使った res/layout/ 以下のレイアウトファイルの内容を挙げておきます。

<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android" ...>
   <TextView
        android:id="@+id/text"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_centerHorizontal="true"
        android:layout_centerVertical="true"
        android:textSize="30dp"
   />
</RelativeLayout>

AndroidHttpClientの使用

HTTPリクエストを発行してレスポンスを受け取るという処理自体には特別なところはありません。
こんな感じ:

import android.net.http.AndroidHttpClient;
import org.apache.http.client.methods.HttpGet;
import org.apache.http.HttpResponse;
    ...
    AndroidHttpClient httpClient = AndroidHttpClient.newInstance("User Agent");
    HttpGet request = new HttpGet("http://www.example.net:8080/");
    HttpResponse response = null;
    try {
        response = httpClient.execute(request);
    } catch (IOException e) {
        e.printStackTrace();
    }

ただし、前述した通りUIスレッドとは別スレッドで実行する必要があることと、HTTPレスポンスからのボディの取り出しのために若干の手を加える必要があります。

AsyncTaskによるバックグラウンド実行

HTTP GETを別スレッドで実行し、実行結果をUIスレッドで画面に表示するという動作を実現するために、このような動作のために用意されているAsyncTaskを利用します。AsyncTaskはジェネリクスを全面的に使っているので最初戸惑いましたが、おそらく慣れたらそれほど難しいものではないと思います。

import android.os.AsyncTask;
import android.net.http.AndroidHttpClient;
import org.apache.http.client.methods.HttpGet;
import org.apache.http.HttpResponse;
...
public class HttpDemo extends Activity {
    TextView textView;

    @Override
    public void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.http_demo);
    this.textView = (TextView) findViewById(R.id.text);

    HttpGet request = new HttpGet("http://www.example.net:8080/");
    new HttpGetTask().execute(request); // AsyncTaskを使って定義したタスクを呼び出す

    // AsyncTaskのサブクラスとして、バックグラウンド処理用のタスクを記述
    class HttpGetTask extends AsyncTask<HttpUriRequest, Void, HttpResponse> {
        // doInBackground() に、バックグラウンド処理の内容を記述する。
        // ここではAndroidHttpClientによるHTTP GET実行
        protected HttpResponse doInBackground(HttpUriRequest... request) {
            AndroidHttpClient httpClient = AndroidHttpClient.newInstance("Demo AndroidHttpClient");
            HttpResponse response = null;
	    try {
                response = httpClient.execute(request[0]);
            } catch (IOException e) {
                e.printStackTrace();
            }
            return response;
        }

        // onPostExecute() に、バックグラウンド処理完了時の処理を記述する。
        // ここでは、HTTPレスポンスボディとして取得した文字列のTextViewへの貼り付け
        protected void onPostExecute(HttpResponse response) {
          .... // この部分の処理は後述
        }
    }
}

Commons IOを用いたHTTPレスポンスから文字列への変換

AndroidHttpClientでHTTP GETの結果として得られるHttpResponseオブジェクトからレスポンスボディを取り出すには、response.getEntity().getContent() で行けます。しかしながら、この結果として得られるのはInputStreamオブジェクトであり、文字列として取り出したい場合には変換に一手間かかります。

InputStream→String の変換は、Apache Commons IOライブラリで実現できるようなので、今回は安直にこれを使いました。Commons IOの配布に含まれるcommons-io-2.4.jarを、Androidのプロジェクト内の libs/ ディレクトリに置くと使えます。

Commons IOを使ってHTTPレスポンスボディ中の文字列を抽出し、その結果をTextViewに貼り付ける部分のコードは以下のようになります。

import org.apache.commons.io.IOUtils;
....
public class HttpDemo extends Activity {
    ....
    class HttpGetTask extends AsyncTask<HttpUriRequest, Void, HttpResponse> {
        ....
        protected void onPostExecute(HttpResponse response) {
            String message = "";
            try {
                InputStream content = response.getEntity().getContent();
                message = IOUtils.toString(content); // Commons IOを用いてInputStream→String変換
            } catch (IOException e) {
                e.printStackTrace();
            }
            textView.setText(message);
        }
    }
}

実行

今回は、以下のような簡単なHTTPサーバをnode.jsで作成して、作成したAndroidアプリから読む込んでみました。もちろんApacheなどを使っても良いと思います。

var http = require('http');
var server = http.createServer(function(req, res) {
   res.writeHead(200, {'Content-Type': 'text/plain'});
   res.write('Hello Internet\n');
   res.end();
});
server.listen(8080);

この状態で、作成したサンプルプログラムを動かすと、無事HTTPで取得した文字列が表示されました。