コンテンツを非同期でサーバー送信する


DefaultHttpClientを使ってコンテンツを取得するではDefaultHttpClientをつかってHTTPリクエスト(Get)を処理しました。
今回はPostリクエストを行い、サーバーへコンテンツを送ってみます。また、前回では簡単化のために説明を省いていましたが、HTTPリクエストなど非同期通信処理はUIスレッド以外で実施しないと、レスポンスが悪化したり、強制終了(ANR)の原因となったりします。Postリクエスト処理時にAsynctaskを使って非同期処理を行うのように、AsyncTaskで別スレッドを作成、非同期化を行うまでを解説します。

  1. HTTPリクエスト Postメソッド
  2. AsyncTaskによる非同期処理化

サンプルコードは続きから。

1.HTTPリクエスト Postメソッドの実装

DefaultHttpClientをつかってコンテンツを送信してみましょう。以下のサンプルはAndroid端末からWebサービスに対して、”content”として文字列をPOSTで送信する、という内容です。
受信時と異なるところが中心ですので、前回の記事と合わせて確認してください。
サンプルコード:

		String url="http://localhost:8888/test";
		HttpClient httpClient = new DefaultHttpClient();
		HttpPost post = new HttpPost(url);

		ArrayList <NameValuePair> params = new ArrayList <NameValuePair>();
		params.add( new BasicNameValuePair("content", contents[0]));

		HttpResponse res = null;

		try {
			post.setEntity(new UrlEncodedFormEntity(params, "utf-8"));
			res = httpClient.execute(post);
		} catch (IOException e) {
			e.printStackTrace();
		}

データ送信準備

3行目:DefaultHttpClientインスタンスとは別にHttpPostクラスのpostインスタンスを作成します。
5行目:HttpPostクラスではPOST処理を行うための変数が設定できます。まずはPOSTしたいArrayListを作成します。
POSTしたいデータ種別に依存しますが通常は名前-値の組み合わせであるNameValuePairを使います。

パラメータ設定

6行目:”content”という名前の文字列”テスト文字列”をparamsインスタンスに追加します。渡したい引数の数に応じてリストに要素を追加してください。
11行目:ArrayListのparamsは、UrlEncodedFormEntityクラスをつかってURIエンコードします。
サーバー側に依存する第2引数は今回の場合は”utf-8″エンコードです(サーバーに合わせて設定してください)。URIエンコードされたインスタンスを生成できました。
12行目:そのままHttpPost#setEntityメソッドに渡して、処理を実行します。

POST処理

11-12行目は失敗する場合もあるため、try~catchにてエラー処理を実装します(本来なら追加すべきですが、サンプルではエラー処理を省略してStackTraceのみ表示しています)。
上記でデータ送信は完了しました。送信結果はHttpResponseクラスのインスタンスresで確認できます。

2.AsyncTaskによる非同期処理化

ここまでで、データの送信処理が完了しました。つづいて非同期処理です。通信に限らず、時間がかかる重たい動作、ブロッキングメソッドはUIスレッドを鈍くします。
たとえばAsynctaskを使って非同期処理を行うでは時間のかかる例として画像のモノクロ処理を題材に扱っています。

今回、非同期通信に利用したAsyncTaskは一度executeしてしまうと再利用できない作りになっているため再実行しないよう注意が必要です。
何度も行う処理の場合は、毎回インスタンスを作成し直す必要があります。(IntentServiceを使って非同期処理を行うでIntentServiceとAsyncTaskの差分を説明しています)

以下はActivityのボタンを押したときにHttpメソッドのPost処理を行うサンプルコード(SeizonSenryaku.java / PostMessageTask.java)です。
SeizonSenryaku.java

    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.main);

        Button btn = (Button)findViewById(R.id.button1);
		final EditText edit = (EditText)findViewById(R.id.editText1);

		btn.setOnClickListener(new OnClickListener() {

			public void onClick(View v) {

		        SpannableStringBuilder sb = (SpannableStringBuilder)edit.getText();
		        String str = sb.toString();

		        PostMessageTask post = new PostMessageTask();
				post.execute( str );
			}
		});
    }

15-16行目:AsyncTaskを継承したPostMessageTaskを実行します(PostMessageTask内部の実装は後述)

PostMessageTask.java

public class PostMessageTask extends AsyncTask<String, Integer, Integer> {

	@Override
	protected Integer doInBackground(String... contents) {
		String url="http://localhost:8888/test";
		HttpClient httpClient = new DefaultHttpClient();
		HttpPost post = new HttpPost(url);

		ArrayList <NameValuePair> params = new ArrayList <NameValuePair>();
		params.add( new BasicNameValuePair("content", contents[0]));

		HttpResponse res = null;

		try {
			post.setEntity(new UrlEncodedFormEntity(params, "utf-8"));
			res = httpClient.execute(post);
		} catch (IOException e) {
			e.printStackTrace();
		}

		return Integer.valueOf(res.getStatusLine().getStatusCode());
	}

}

PostMessageTaskはAsyncTaskと同じなので、doInBackgroundメソッドでコンテンツを送信します(HTTPリクエスト(POSTメソッド)を実行する)。
内部6-22行目の間が最初の項「HTTPリクエスト Postメソッドの実装」で紹介したHTTPリクエスト処理にあたります(処理内容が同じですね)。
送信完了をユーザに伝える場合(処理に失敗してリトライが必要な場合)などは、AsyncTaskクラスのonPostExecuteメソッドを使うことで後処理を追加できます。

今回はより実際の実装に近い、別スレッドを使って、サーバーへのコンテンツ送信する方法を紹介しました。
おつかれさまでした。

3 Comments