[[勉強会]]

* Androidでorg.apache.http.clientを使用する [#u256e3d3]

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

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

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


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

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

** 手順2:プロジェクトを作成しましょう [#d831cd13]
googleに検索クエリを発行するためのプロジェクトを作成します。
- "File -> New -> Project"を選択して、開いたダイアログで"Android Poroject"を選択して、"Next"ボタンを押します。
- 開いたダイアログで、以下のように入力してFinishボタンを押します。
-- Project Name: HelloHTML
-- Package name: net.it4myself.hellohtml
-- Activity Name: .HelloHTML
-- Application Name: ハローHTML


** 手順3:マニフェストファイルを設定する [#q3055b2a]

- このプロジェクトではインターネットにアクセスするため、パーミッションの使用を許可する必要があります。
- もう慣れましたね? ソースだけ貼っておきます。

 <?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:レイアウトを決定する [#tae13375]
画面のレイアウトを決定するために、res/layout/main.xmlを編集しましょう。
- これも今回のチュートリアルの趣旨から外れるので、ソースだけ貼っておきます。
- ちなみに[[DroidDraw:http://droiddraw.org/]]で作ったものです。ちなみにちなみに、スタンドアローン版の方が高機能です!

 <?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で作ったプロジェクトをビルドパスに加える [#b1c146e4]
別のプロジェクト内にあるパッケージを使用するので、ビルドパスの設定をする必要があります。これを忘れてしまうと、net.it4myself.util.RestfulClientクラスは使用できません。
- HelloHTMLプロジェクト上で右クリックして、"Properties"を選択します
- 表示されたダイアログボックスで"Java Build Path"を選択します()
- "Projects"タブを選択します()
- "Add..."ボタンをクリックし、"android_utils"プロジェクトを選択します()
- "android_utils"が追加されたことを確認します()
- OKボタンをクリックして設定を完了します()
#ref(httpclient.add_build_path.jpg)


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

- 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 input = (EditText)findViewById(R.id.query_text); 
             	EditText queryStringEdit = (EditText)findViewById(R.id.query_text); 
		TextView html_source =  (TextView)findViewById(R.id.html_source);
                String queryString = "http://www.google.com/search?q=" + input.getText().toString();
                String uri = "http://www.google.com/search?q=" + queryStringEdit.getText().toString();
                try {
                    String html = RestfulClient.Get(queryString, null);
                    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()の内容を確認する [#tdfd5d90]
shared_android_utilsプロジェクトを開き、srcの下のnet.it4myself.utilのRestfulClient.javaを開いて内容を確認します。
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);
     }
   }


-----
[[勉強会]]