こんにちはー。管理人のピヨ猫でーす。
WebアプリケーションだとWebサーバーからデータを取り出してブラウザに表示するじゃん。Androidアプリでも同じ様にサーバからデータを取りたいと思うんだけどどうやってやれば良いのかな?
AndroidにはHttpURLConnectionというサーバーサイドと連携する仕組みが備わっているよ。HttpURLConnectionの使い方を説明するね。
1.HttpURLConnectionとは?
HttpURLConnectionはAndroidアプリの開発プログラムであるJavaに備わっているHTTP通信を行うためのモジュールです。AndroidアプリからもJavaのHttpURLConnectionを使うことでサーバーサイドとHTTP通信を行うことが出来ます。
【HttpURLConnectionリファレンス】
https://docs.oracle.com/javase/jp/8/docs/api/java/net/HttpURLConnection.html
2.AndroidアプリのHTTP通信処理の流れ
AndroidアプリのHTTP通信処理の流れ
こんな感じです。
AndroidアプリにおけるHTTP通信のポイント
HTTP通信は非同期通信とする
同期通信にすると全く反応が無いアプリが出来上がってしまう可能性があるため、AndroidアプリでのHTTP通信は非同期で行う必要があります。
同期通信とすると実行時にエラーになります。android開発者サイトにもHTTP通信は非同期でやるようにと記載されています。
https://developer.android.com/training/basics/network-ops/connecting.html
HTTP通信処理は共通モジュールとした方が便利
HttpURLConnectionを使ったHTTP通信では、サーバーサイドの処理の呼び出しだけでなく、結果をコールバック関数で受け取ったり、サーバーサイドと通信中は砂時計を表示したりする必要があります。
Androidアプリ開発でHTTP通信処理は頻繁に使うので、使い易い共通クラスを用意しておいた方が便利です。
参考として管理人のぴよ猫が使っている共通クラス「HttpRequestor」のソースと使い方をこれから紹介します。
3.HttpRequestorを使った実装サンプル
1.HTTP通信を行うための準備
AndroidManifestの設定
Androidでインターネットに接続するためにはマニュフェストにインターフェース接続の設定を追加する必要があります。
【AndroidManifestの設定方法】
<manifest・・・>
<application ・・・>
・・・
</application>
<!-- 通信の許可 -->
<uses-permission android:name="android.permission.INTERNET" />
</manifest>
ラムダの設定
これから紹介するソースはJava8からサポートされたラムダ式を使用します。ラムダ式を使用した方がシンプルでバグの発生し辛いプログラムを記述できるためです。
Androidの開発でラムダ式を使うためには、Android StudioのコンパイルオプションをデフォルトのJava7からJava8に変更する必要があります。具体的にはbuild.gradleを以下の様に設定します。
【build.gradle (Module: app)】
android {
・・・
compileOptions {
sourceCompatibility JavaVersion.VERSION_1_8
targetCompatibility JavaVersion.VERSION_1_8
}
}
2.HTTP通信を行うための共通クラスHttpRequestorの作成
HttpRequestorクラスを作成します。ソースは以下の通りです。処理の意味はコメントを参照ください。
【HttpRequestor.java】
import android.app.ProgressDialog;
import android.content.Context;
import android.os.AsyncTask;
import android.support.v4.util.Consumer;
import android.util.Log;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.net.HttpURLConnection;
import java.net.URL;
/**
* 非同期通信HTTPリクエスト実行クラス<br />
* <p>[使用方法]</p>
* new HttpRequestor(
* this,
* "http://xxxx.xx",
* "処理中メッセージ",
* b -> {
* // rはバイト配列のレスポンスデータ。
* // 正常時の処理を記載。
* },
* e -> {
* // eはエクセプション。
* // エラー時の処理を記載。
* }
* ).execute();
*/
public class HttpRequestor extends AsyncTask<Void, Void, byte[]> {
private Context context = null;
private String url = null;
private String message = null;
private Consumer<byte[]> callback = null;
private Consumer<Exception> errorCallback = null;
private Exception exception = null;
private ProgressDialog progressDialog = null;
/**
* コンストラクタ
* @param context コンテキスト
* @param url 通信先URL
* @param message 処理中メッセージ
* @param callback 正常時のコールバック関数(Consumer<byte[]>)
* @param errorCallback エラー時のコールバック関数(Consumer<Exception>)
*/
public HttpRequestor(Context context,
String url,
String message,
Consumer<byte[]> callback,
Consumer<Exception> errorCallback) {
this.context = context;
this.url = url;
this.message = message;
this.callback = callback;
this.errorCallback = errorCallback;
}
@Override
protected void onPreExecute() {
// 砂時計表示
this.progressDialog = new ProgressDialog(context);
this.progressDialog.setProgressStyle(ProgressDialog.STYLE_SPINNER);
this.progressDialog.setMessage(this.message);
progressDialog.setCancelable(false);
this.progressDialog.show();
super.onPreExecute();
}
@Override
protected byte[] doInBackground(Void... params) {
HttpURLConnection con = null;
try {
// HTTPリクエスト
final URL url = new URL(this.url);
con = (HttpURLConnection) url.openConnection();
con.connect();
final int status = con.getResponseCode();
if (status == HttpURLConnection.HTTP_OK) {
final InputStream in = con.getInputStream();
ByteArrayOutputStream out = new ByteArrayOutputStream();
byte [] buffer = new byte[1024];
while(true) {
int len = in.read(buffer);
if(len < 0) {
break;
}
out.write(buffer, 0, len);
}
in.close();
out.close();
return out.toByteArray();
} else {
throw new IOException("HTTP status:" + status);
}
} catch (Exception e) {
Log.e("ERROR", e.toString(), e);
this.exception = e;
return null;
} finally {
if (con != null) {
con.disconnect();
}
}
}
@Override
protected void onPostExecute(byte[] response) {
super.onPostExecute(response);
// コールバック処理実行
if (this.exception == null) {
callback.accept(response);
} else {
errorCallback.accept(this.exception);
}
// 砂時計解除
this.progressDialog.dismiss();
}
}
3.HttpRequestorの使い方
HttpRequestorの使い方
HttpRequestor中身の処理の説明の前にHttpRequestorの使い方です。
HTTP通信の処理を実行するうえでは、以下の使い方さえおさえていれば、HttpRequestorの中身の実装を意識する必要はありません。
new HttpRequestor(
this, // コンテキスト
"https://piyonekochannel.com/", // 接続先URL
"読込中...", // 通信中に砂時計に表示するメッセージ
b -> {
// 通信成功時のコールバック処理。bはレスポンスのbyte配列。
text.setText(new String(b));
},
e -> {
// 通信失敗時のコールバック処理。eはException。
text.setText(e.toString());
}
).execute();
}
HttpRequestorを呼び出すサンプルプログラム
【MainActivity.java】
import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;
import android.view.View;
import android.widget.TextView;
import java.io.ByteArrayInputStream;
public class MainActivity extends AppCompatActivity {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
}
public void onClickExecuteButton(View view) {
TextView text = (TextView)findViewById(R.id.result_text);
new HttpRequestor(
this,
"https://piyonekochannel.com/",
"読込中...",
b -> {
text.setText(new String(b));
},
e -> {
text.setText(e.toString());
}
).execute();
}
}
4.HTTP通信が出来るとどんな良いことがあるか?
HTTP通信が出来ると嬉しいこと
- サーバー側にデータを持たせられる
サーバー側にデータを持たせられるので端末を変えた場合でもデータが消えないアプリを開発出来る。 - Google APIなどのクラウドサービスが使えるのでアプリの開発の幅が広がる
- TwiterやLineの様にユーザー間でやり取りが出来るアプリを作れる
などなどサーバー通信が出来るとアプリ開発の幅が広がります。むしろ、HTTP通信は必須と言って良いです。
HTTP通信を使用したアプリの紹介(マイアプリです(-_-;))
どこでも画像検索ドア
Andoroidの音声認識機能とGoogle検索を使って音声で画像を検索するアプリです。
極シンプル ランチャー
アプリやWEBサイトを一括お気に入り登録できるアプリです。fabicon画像(*)の取得のためにGoogleAPIを使用しています。
5.HTTP通信処理の実装の注意点
前章でも述べましたが非同期通信を行う必要があります。なので、前章で紹介した様な処理シーケンスにする必要があります。
当記事を見て、標準コンポーネントのHttpURLConnectionだけじゃダメなの?何でわざわざAsyncTaskを継承した独自クラス(HttpRequestor)を作るの?と思いませんでしたか?
しかし、実はAndroidではHTTP通信をmainスレッドではなくバックグラウンドの別スレッドで非同期に行う必要があります。そのため、AsyncTaskで非同期処理を行う必要があるんです。試しにActivityからHttpURLConnectionしたらエラーになりました(-_-;)
また、上のソースの様にコールバック関数に結果を渡さずにHttpRequestorの中で結果をActivityに設定することも可能ではあるのですが、Activityに依存した処理をHttpRequestorに入れると、HttpRequestorの使いまわしが出来ないので、Activityへの結果反映はコールバック関数にしておいた方が良いです。
なので、良ければ、上述のソース使って下さい。m(_ _)m
AndroidもJQueryみたいにHTTP通信処理を非同期で出来るコンポーネントを標準で提供してくれていれば良いのに・・・(;^_^A
それでは、少しでも本記事がお役に立てたら幸いです。
![]() |
TECHNICAL MASTER はじめてのAndroidアプリ開発 第2版 Android Studio 2対応【電子書籍】[ 山田祥寛 ] 価格:3,110円 |