勉強会

Androidでorg.apache.http.clientを使用する

AndroidでHTTPを使用してネットワークにアクセスするには、org.apache.http.clientパッケージのクラスを使用します。

ただし、使いこなすためにはHTTPプロトコルを多少理解しておく必要があり、独自にヘッダーを設定するなど、特殊な使い方をするのでなければorg.apache.http.clientを直接操作する必要はあまりありません。

ここではandroid用のユーティリティとしてオープンソースで公開されているRestfulClientクラスを使用し、HTTPのGETメソッドを使ってgoogleに検索クエリを投げて結果をHTMLで受け取ってみた後、RestfulClientクラス内の動作を追ってみましょう。

手順1:公開されているandroid用のユーティリティのソースファイルをダウンロードし、Eclipseに登録する

  • ソースファイルはGitHubというサービスを使って公開されていますので、GitHub上のandroid_utilsプロジェクトを開き、downloadボタンからZipファイルをダウンロードします。 (Gitを使える人はgit cloneしてもらった方が今後楽かもしれません)
    httpclient.download_from_github.jpg
  • Eclipseを開き "File -> Import"を選択します。
  • "Generalの中のExisting Projects into workspace"を選択して、"Next"ボタンを押します。
    httpclient.Importtype.jpg
  • ダウンロードしたZipファイル(もしくはgit cloneしたディレクトリ)から、以下のスクリーンショットのようにandroid_utilsプロジェクトをインポートします。一緒にandroid_util_testsプロジェクトもインポートしておいた方か後々楽かも知れません。
    httpclient.ImportFrom.jpg
  • Eclipseにプロジェクトがインポートされていることを確認します。

手順2:プロジェクトを作成しましょう

googleに検索クエリを発行するためのプロジェクトを作成します。

  • "File -> New -> Project"を選択して、開いたダイアログで"Android Poroject"を選択して、"Next"ボタンを押します。
  • 開いたダイアログで、以下のように入力してFinishボタンを押します。
    • Project Name: HelloHTML
    • Package name: net.it4myself.hellohtml
    • Activity Name: .HelloHTML
    • Application Name: ハローHTML

手順3:マニフェストファイルを設定する

  • このプロジェクトではインターネットにアクセスするため、パーミッションの使用を許可する必要があります。
  • もう慣れましたね? ソースだけ貼っておきます。
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
      package="net.it4myself.hellohtml"
      android:versionCode="1"
      android:versionName="1.0.0">
    <application android:icon="@drawable/icon" android:label="@string/app_name">
        <activity android:name=".HelloHTML"
                  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-permission android:name="android.permission.INTERNET"/>
</manifest> 

手順4:レイアウトを決定する

画面のレイアウトを決定するために、res/layout/main.xmlを編集しましょう。

  • これも今回のチュートリアルの趣旨から外れるので、ソースだけ貼っておきます。
  • ちなみにDroidDrawで作ったものです。ちなみにちなみに、スタンドアローン版の方が高機能です!
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout
  android:layout_width="fill_parent"
  android:layout_height="fill_parent"
  android:orientation="vertical"
  xmlns:android="http://schemas.android.com/apk/res/android"
>
<LinearLayout
  android:layout_width="fill_parent"
  android:layout_height="wrap_content"
>
<TextView
  android:layout_width="wrap_content"
  android:layout_height="wrap_content"
  android:hint="Query String"
>
</TextView>
<EditText
  android:id="@+id/query_text"
  android:layout_width="200px"
  android:layout_height="wrap_content"
  android:text="EditText"
  android:textSize="18sp"
>
</EditText>
<Button
  android:id="@+id/search_button"
  android:layout_width="wrap_content"
  android:layout_height="wrap_content"
  android:text="search"
>
</Button>
</LinearLayout>
<TextView
  android:id="@+id/html_source"
  android:layout_width="fill_parent"
  android:layout_height="wrap_content"
  android:text="TextView"
>
</TextView>
</LinearLayout> 

手順5:手順1で作ったプロジェクトをビルドパスに加える

別のプロジェクト内にあるパッケージを使用するので、ビルドパスの設定をする必要があります。これを忘れてしまうと、net.it4myself.util.RestfulClientクラスは使用できません。

  • HelloHTMLプロジェクト上で右クリックして、"Properties"を選択します
  • 表示されたダイアログボックスで"Java Build Path"を選択します()
  • "Projects"タブを選択します()
  • "Add..."ボタンをクリックし、"android_utils"プロジェクトを選択します()
  • "android_utils"が追加されたことを確認します()
  • OKボタンをクリックして設定を完了します()
    httpclient.add_build_path.jpg

手順6:Getメソッドを使ってgoogle検索結果を取得する

  • srcの下のnet.it4myself.hellohtmlのHelloHTML.javaを開いて以下のように入力します。
  • 以下のコードでは、以下の手続きを行っています。
    • search_buttonボタンのOnClickListnerに以下のイベントを仕込む
      • "http://www.google.com/search?q="とquery_textエディットテキストの入力内容を連結させ、アクセスするURLを生成する
      • RestfulClient.Get()を呼ぶ。第一引数はURL。第二引数はパラメータだが、URLにクエリーストリングを含めたのでnullとしている。
      • RestfulClient.Get()の返値として検索結果のHTMLが返ってくるので、html_sourceテキストビューにセットする。
package net.it4myself.hellohtml;

import java.io.IOException;

import org.apache.http.client.ClientProtocolException; 

import net.it4myself.util.RestfulClient;
import android.app.Activity;
import android.os.Bundle;
import android.view.View;
import android.widget.Button;
import android.widget.EditText;
import android.widget.TextView; 

public class HelloHTML extends Activity {
    /** Called when the activity is first created. */
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.main);
        
        Button b = (Button)findViewById(R.id.search_button);
        b.setOnClickListener(new View.OnClickListener() {
           public void onClick(View v) {
            	EditText queryStringEdit = (EditText)findViewById(R.id.query_text); 
		TextView html_source =  (TextView)findViewById(R.id.html_source);
               String uri = "http://www.google.com/search?q=" + queryStringEdit.getText().toString();
               try {
                   String html = RestfulClient.Get(uri, null);
                   html_source.setText(html);
               } catch (ClientProtocolException e) {
                   e.printStackTrace();
                   html_source.setText("error1");
               } catch (IOException e) {
                   e.printStackTrace();
                   html_source.setText("error2");
               }
           }
        });
    }
}
  • プロジェクトを右クリックして、"Run As"->"Android Application"で実行してみましょう。Queryの内容に応じて、表示されるHTMLの内容が異なっているはずです。

RestfulClient.Get()の内容を確認する

android_utilsプロジェクトを開き、srcの下のnet.it4myself.utilのRestfulClient.javaを開いて内容を確認します。 RestfulClientクラスの場合、返値がStringかDOMオブジェクトかによってオーパロードさせていますが、基本的な流れは同じです。ここでは基本的な流れを解説します。

  • (A) HTTPプロトコルを使ってアクセスする場合、最も簡単なのはorg.apache.http.impl.clientパッケージのDefaultHttpClientクラスを使用することです。DefaultHttpClientクラスはHTTPプロトコルに対応し、(RestfulClinetクラスでは使用していませんが)SSLやベーシック認証のための設定などを行うことが出来ます。RestfulClinetクラスではDoRequest()メソッドでこのインスタンスを生成しています。
  • (B) このDefaultHttpClientクラスのexecuteメソッドに、HttpGetのインスタンスやHttpPostのインスタンスを渡すことで、HTTPプロトコルの各メソッド特有の設定を行います。RestfulClinetクラスではDoRequest()の引数として渡ってきます。
  • (C) DefaultHttpClientクラスのexecuteメソッドの戻り値は、HttpResponseです。戻り値からはHTTPプロトコルのレスポンスコード(200 OKなど)やInputStreamを取り出せます。RestfulClinetクラスではEntityを取り出し、それをEntityUtils.toString()を使って文字列化するか、getDOM()メソッド内でXMLとしてパースしてDOMオブジェクトを取り出しています。
  • 参考にソースも張っておきます。
      public static String Get(String uri, HashMap<String,String> map) throws ClientProtocolException, IOException {
        String fulluri;
    
        if(null == map){
          fulluri = uri;
        } else {
          fulluri = uri + packQueryString(map);
        }
        HttpGet method = new HttpGet(fulluri);
        return EntityUtils.toString(DoRequest(method));
      }
      
      private static HttpEntity DoRequest(HttpUriRequest method) throws ClientProtocolException, IOException {
        HttpClient client = new DefaultHttpClient(); // (A)
    
        // BASIC認証用のユーザ名が設定されていれば、BASIC認証を行う
        if(!basicAuthUsername.equals("")){
            URI uri = method.getURI();
            client.getCredentialsProvider().setCredentials(
    	     new AuthScope(uri.getHost(), uri.getPort()),
    	     new UsernamePasswordCredentials(basicAuthUsername, basicAuthPassword));
        }
    
        HttpResponse response = null;
    		
        try {
          response = client.execute(method); // (B)
          int statuscode = response.getStatusLine().getStatusCode(); // 以下(C)
    			
          //リクエストが成功 200 OK and 201 CREATED
          if (statuscode == HttpStatus.SC_OK | statuscode == HttpStatus.SC_CREATED){ 
            return response.getEntity();
          } else {
            throw new HttpResponseException(statuscode, "Response code is " + Integer.toString(statuscode));
          }
        }catch (RuntimeException e) {
          method.abort();
          Log.v(TAG, e.getMessage());
          throw new RuntimeException(e);
        }
      }

勉強会