AndroidアプリからサーバーにHTTP通信する場合の備忘録です。
(androidはまだ勉強を始めたばかりで理解が十分でないので、間違っている部分も多々あると思います。
間違いに気づいた時点で修正していくつもりです。)
Androidアプリでサーバーと非同期通信処理を行うためには、AsyncTaskを継承したクラスを作成します。
AsyncTaskに用意されている以下のメソッドを必要に応じてオーバーライドします。
(1)onPreExecute() ・・・ タスク実行前にUIスレッドで実行される。事前準備の処理を実装する。(例:プログレスバー表示)
(2)doInBackground() ・・・ バックグラウンドスレッドで実行される。実装必須。
(3)onProgressUpdate() ・・・ doInBackGround()でpublishProgress()が呼ばれた場合に実行される。(例:進行状況表示)
(4)onPostExecute() ・・・ バックグラウンド処理が終了したときに実行される。結果をUIスレッドに反映する処理を実装する。
今回は、サーバーにPOSTして結果をJSONもしくは画像を受信することを想定しているので
レスポンスはどちらでも対応できるようにInputStreamを返却しています。
サーバーと通信を行うクラスは、マルチパート形式に対応しています。
マルチパート形式に対応するためには、以下のライブラリの追加が必要です。
・httpmime-x.x.x.jar
http://hc.apache.org/downloads.cgi ⇒ HttpClient x.x.x (GA) の項目よりダウンロード
(今回私は、httpmime-4.3.3.jarとhttpcore-4.3.2.jarを追加しました。)
非同期で通信してレスポンスを起動元に返却するためにコールバックを定義しています。
コールバック定義
1 2 3 4 5 |
import java.io.InputStream; public interface AsyncCallback { void onPostExecute(InputStream response); } |
呼び出し側
(※Fragment)
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 |
// ネットワーク接続チェック ConnectivityManager cm = (ConnectivityManager)getActivity().getApplicationContext().getSystemService(Context.CONNECTIVITY_SERVICE); if ( ! HttpConnector.isConnected(cm) ) { new AlertDialog.Builder(getActivity()) .setMessage("インターネットに接続できませんでした。ネットワーク接続状況を確認してください。") .setPositiveButton("OK", null) .show(); return; } // サーバーにリクエスト送信 HttpConnector.RequestInfo requestInfo = new HttpConnector.RequestInfo(); requestInfo.url = "https://example.com/sample.php"; requestInfo.params.add(new HttpConnector.Param(HttpConnector.Param.TYPE_STRING, "key_param1", "value_param1")); requestInfo.params.add(new HttpConnector.Param(HttpConnector.Param.TYPE_STRING, "key_param2", "value_param2")); requestInfo.asyncCallback = new AsyncCallback() { // コールバックメソッド @Override public void onPostExecute(InputStream responseIS) { BufferedReader reader = new BufferedReader(new InputStreamReader(responseIS)); StringBuilder buf = new StringBuilder(); String line; try { while ( (line = reader.readLine()) != null ) { buf.append(line); } } catch (IOException e) { e.printStackTrace(); return; } String responseStr = buf.toString(); JSONObject jsonObj = null; try { jsonObj = new JSONObject(response); } catch (JSONException e) { e.printStackTrace(); return; } …(略)… } }; HttpConnector.Request(getActivity(), requestInfo); |
サーバーと通信を行うクラス
MultipartEntity は Deprecated(4.3)となっていたので、
代わりに MultipartEntityBuilderを使用しています。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 |
public class HttpConnector { /* ネットワーク接続有無 */ public static boolean isConnected(ConnectivityManager manager) { NetworkInfo info = manager.getActiveNetworkInfo(); if ( info == null ) { return false; } return info.isConnected(); } /* リクエスト情報クラス */ public static class RequestInfo { public String url = null; public List<Param> params = new ArrayList<Param>(); public AsyncCallback asyncCallback = null; } /* Postパラメータ情報クラス */ public static class Param { public static final int TYPE_STRING = 1; public static final int TYPE_IMAGE = 2; private int type; private String key; private String value; public Param(int type, String key, String value) { this.type = type; this.key = key; this.value = value; } } /* リクエスト呼び出しクラス */ public static void Request(Context context, RequestInfo requestInfo) { AsyncHttpRequest asyncHttpRequest = new AsyncHttpRequest(context); asyncHttpRequest.url = requestInfo.url; if ( requestInfo.params != null ) { asyncHttpRequest.params.addAll(requestInfo.params); } // リクエスト実行 asyncHttpRequest.execute(); } /* リクエスト実行本体 */ private static class AsyncHttpRequest extends AsyncTask<Void, Void, InputStream> { private Context context = null; private String url = null; private List<Param> params = new ArrayList<Param>(); private AsyncCallback asyncCallback = null; private ProgressDialog progressDialog; public AsyncHttpRequest(Context context) { this.context = context; } @Override protected void onPreExecute() { progressDialog = new ProgressDialog(context); progressDialog.setProgressStyle(ProgressDialog.STYLE_SPINNER); progressDialog.setMessage("サーバーに接続中..."); progressDialog.show(); } @Override protected InputStream doInBackground(Void... params) { URI uri = null; try { uri = new URI(url); } catch (URISyntaxException e) { e.printStackTrace(); return null; } HttpUriRequest request = null; if ( this.params != null && this.params.size() > 0 ) { HttpPost post = new HttpPost(uri); MultipartEntityBuilder entity = MultipartEntityBuilder.create(); entity.setMode(HttpMultipartMode.BROWSER_COMPATIBLE); entity.setCharset(Consts.UTF_8); for ( Param p:this.params ) { switch ( p.type ) { case Param.TYPE_STRING: ContentType textContentType = ContentType.create("text/plain"); entity.addTextBody(p.key, p.value, textContentType); break; case Param.TYPE_IMAGE: ContentType imageContentType = ContentType.create("image/jpg"); entity.addBinaryBody("image", new File(p.value), imageContentType, p.value); break; } } post.setEntity(entity.build()); request = post; } HttpClient httpClient = new DefaultHttpClient(); try { httpClient.execute(request, new ResponseHandler<InputStream>() { @Override public InputStream handleResponse(HttpResponse response) throws ClientProtocolException, IOException { switch (response.getStatusLine().getStatusCode()) { case HttpStatus.SC_OK: return new BufferedHttpEntity(response.getEntity()).getContent(); case HttpStatus.SC_NOT_FOUND: throw new RuntimeException("httpClient.execute SC_NOT_FOUND"); default: throw new RuntimeException("httpClient.execute error!"); } } }); } catch (ClientProtocolException e) { e.printStackTrace(); } catch (IOException e) { e.printStackTrace(); } finally { if ( httpClient != null ) { try { httpClient.getConnectionManager().shutdown(); } catch (Exception e) { e.printStackTrace(); } } } return null; } @Override protected void onPostExecute(InputStream responseIS) { // プロセスダイアログ表示終了 if ( this.progressDialog != null && this.progressDialog.isShowing() ) { this.progressDialog.dismiss(); } // 起動元をコールバック if ( this.asyncCallback != null && responseIS != null ) { this.asyncCallback.onPostExecute(responseIS); } } } } |
AsyncTaskLoaderやVolleyを利用する方法もあるらしいので、勉強してみようと思います。
【2014/04/11 追記】
Volleyについての記事を書きました。⇒ ネットワーク通信ライブラリ Volley