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アクセス
##インターネット接続許可を与える

```xml: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リクエストの際のサンプルコード

```java
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処理の際のサンプルコード

```java
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);
            }

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