Java
Android

Android開発〜WEBアクセス(GET)外部と通信してデータを取得してみる。〜

はじめに

こんにちは。某学校でプログラミング等の勉強中のサーバーサイドのプログラマーのワタタクです。:relaxed:
今回もAndroid開発していきましょう。
今回はAndroidで外部のネットワークと接続してデータを取得してみたいと思います。

対象者

  • Javaがそこそこ書ける人。
  • Android開発においてもそこそこできる人。

Webアクセス概要

1) アプリ内で http アクセスのソースコードを記述する。 → レスポンスの内容は JSON か XML が多い。
2) 画面内で画面部品 WebView を使う。 → レスポンスの内容は原則 HTML。

非同期処理

Webアクセスのように、処理に時間がかかるもの、予期せぬエラーが起こりそうなもおは、 メイン処理とは別のスレッドで処理(非同期処理)を行う。

AsyncTask

Androidの非同期処理のうち、UIスレッドとやりとりがある場合は、AsyucTaskクラスを使うと便利。

1.AsyncTaskの使い方

1) Asynuc Task を継承したクラスを作成する。
→ アクティビティクラスの private メンバクラスとして作ると便利。

2) メソッド doInBackground() 内に非同期で行いたい処理を記述する。
→ このメソッドは Asyuc Task の抽象メソッドなので、必ずオーバーライドする必要がある。

3) アクティビティでこのクラスを newして、execute() メソッドを実行する

private class クラス名 extends AsyucTask< ... > {
  ...
  @Override
  public String doInBackground( String ... params ) {    
     // ここに非同期処理を記述
  }
}
その後
クラス名 変数名 = new クラス名(); 
変数名.execute( ... );

*メソッドの引数にある「...」( ドット 3 コ ) は可変長引数を表す。
メソッド内での引数の扱いは配列となる。

2.その他のメソッド

AsyucTask には doInBackground() 以外にも以下のメソッドがある。
これらのメソッドは UI スレッド上で実行されるので、画面部品の操作が可能。

  • onPostExecute() : doInBackground() の終了後に実行される。
  • onPreExecute() : doInBackground() の開始前に実行される。
  • onProgressUpdate() : doInBackground() の中で publishProgress() を呼び出した時に実行される。

さらに、アクティビティから cancel() が呼び出されると、doInBackground() 終了後、 onCancelled() が実行される。

3.ジェネリクス

AsyucTask の子クラスを作るとき、ジェネリクスに 3 個の型を書く必要がある。
型指定が不要なものは Void と記述。

...クラス名 extends AsyucTask<①String, ②Void, ③String> {

①Params

execute() . doInBackground() の引数の型。
→ execute() の引数がそのまま doInBackground() の引数として渡される

②Progress

publishProgress() . onProgressUpdate() の引数の型。
→ publishProgress() の引数が、そのまま onProgressUpdate() の引数として渡される。

③Result

doInBackground() の戻り値、および、onPostExecute() . onCanceled() の引数の型。 → doInBackground() の戻り値は、そのまま、onPostExecute() や onCanceled() の引数 として渡される。

httpアクセス

インターネット接続許可を与える

src/main/AndroidManifest.xml
<uses-permission android:name="android.permission.INTERNET"/>
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE"/>

もし許可を与えずにインターネット通信を行うとjava.net.SocketException: socket failed: EACCES (Permission denied)の例外が発生します。

インターネットに接続する

HttpURLConnectionオブジェクトを使います。

URL文字列をセットする。

URL url = new URL("URL文字列");

コネクションの取得

con = (HttpURLConnection) url.openConnection();

アクセス先URL情報を持ったURLオブジェクトに対してURL#openConnection()メソッドを実行すると、HttpURLConnectionオブジェクト(コネクション)を取得することができます。

アクセス方法の設定

setRequestMethod()を使います。
*今回はデータ取得のため"GET"

con.setRequestMethod("GET")

実際にインターネット接続

URLConnection#connect()を使います。

con.connect();

コネクションの切断

disconnect()を使います。
処理終了後は、不要なコネクションを残さないために、明示的にコネクションを切断してあげる必要があります。

con.disconnect()

httpリクエストの際のサンプルコード

private class クラス名 extends AsyncTask<String, Void, String> {
        private static final String DEBUG_TAG = "タグ";

        @Override
        public String doInBackground(String... params) {
            String urlStr = params[0];
            String id = params[1];

            HttpURLConnection con = null;
            InputStream is = null;
            String result = "";

            try {
                URL url = new URL(urlStr);
                con = (HttpURLConnection) url.openConnection();
                con.setRequestMethod("GET");
                con.connect();
                is = con.getInputStream();

                result = is2String(is);
            }
            catch(MalformedURLException ex) {
                Log.e(DEBUG_TAG, "URL変換失敗", ex);
            }
            catch(IOException ex) {
                Log.e(DEBUG_TAG, "通信失敗", ex);
            }
            finally {
                if (con != null) {
                    con.disconnect();
                }
                if (is != null) {
                    try {
                        is.close();
                    }
                    catch (IOException ex) {
                        Log.e(DEBUG_TAG, "InputStream解除失敗", ex);
                    }
                }
            }
            return result;
        }

        private String is2String(InputStream is) throws IOException {
            BufferedReader reader = new BufferedReader(new InputStreamReader(is, "UTF-8"));
            StringBuffer sb = new StringBuffer();
            char[] b = new char[1024];
            int line;
            while(0 <= (line = reader.read(b))) {
                sb.append(b, 0, line);
            }
            return sb.toString();
        }
}

InputStreamはバイトを読み込むためのクラス。
*is2Strクラスはおまじないみたいなものとして書いておいてください。理由はわかりません。わかる人は教えてください。

JSONの扱い

JSONObjectクラスを使います。
引数として「JSON文字列」を指定します。

その後、以下の操作を行いながら、目的の JSONObject を取得し、getString( ... ) で値を取得する。

  • 直下の JSONObject の取得は、getJSONObject( ... )
  • 直下の JSONArray( JSON 配列 ) の取得は、getJSONArray( ... )
  • JSONArray の指定の JSONObject の取得は、getJSONObject( ... )

JSON処理の際のサンプルコード

private class クラス名 extends AsyncTask<String, Void, String> {


 @Override
 public void onPostExecute(String result) {
            String title = "";
            String text = "";
            String dateLabel = "";
            String telop = "";
            try {
                JSONObject rootJSON = new JSONObject(result);
                title = rootJSON.getString("title");
                JSONObject descriptionJSON = rootJSON.getJSONObject("description");
                text = descriptionJSON.getString("text");
                JSONArray forecasts = rootJSON.getJSONArray("forecasts");
                JSONObject forecastNow = forecasts.getJSONObject(0);
                dateLabel = forecastNow.getString("dateLabel");
                telop = forecastNow.getString("telop");
            }
            catch(JSONException ex) {
                Log.e(DEBUG_TAG, "JSON解析失敗", ex);
            }

   }
}

以上。
もし何か間違っている等のご指摘があればご連絡ください。
最後まで読んで頂きありがとうございました。