HTTPでGETするAndroidアプリを作ってみた


先日[こんな記事](http://qiita.com/syoutin/items/15ff3d9665a7fe648446)を書いたAndroidアプリ開発初心者です。今日覚えたことをメモしておきます。

##注意
この記事は、初学者が自分の学習したことをメモしておくために書いたものです。
実装のお作法とか、常識的なやり方からは逸脱している可能性がクッソ高いので、実装の参考にする際はくれぐれもご注意をというか自己責任というかやめたほうがいいとおもう

##今日覚えたこと
・ いまいまAndroidアプリからHTTP/GETのリクエストを投げるのは、HttpUrlConnectionてのを使うのがいいっぽい->[reference](https://developer.android.com/reference/java/net/HttpURLConnection.html)

・ AndroidアプリではHTTP通信は非同期で実装する必要がある。アプリ本体を動かしてるスレッドとは別のスレッドで通信をする必要がある。

・ アプリのUIをいじるのはメインスレッドであり、別スレッドからメインスレッドは弄れない（UIをいじれない） -> 工夫がいる

いろいろ躓いてますが、一歩ずつコーディングしながらお勉強！

##この記事では解説してないこと
今回リクエストを投げる先は、自分で作ったサーバに自分で実装したPHPで、適当なGETリクエストに対して適当に結果をjsonで返してくれるプログラムです。この記事ではそちらには触れないし、その実装も書いてません。別に書こう。


##今日作ったもの

こんなUIで、上部のeditTextに入力されたURIに対してGETでリクエストを投げて、結果が得られたら下のeditTextにレスポンスボディを書きだす

![1.png](https://qiita-image-store.s3.amazonaws.com/0/51774/8618c920-b196-d2e4-d94e-bf56b713253a.png)

「Request URL」はただのTextView。置いてあるだけ。
いまこの記事書いてておもったけど、これURLじゃなくてURIだけどどっちでもいいや

これと、GETて書いてあるボタンの間の隙間がeditTextUrl。このURL（URI)に対して、GETのリクエストを投げてみます。
GETのボタンはただのボタン。onClickでメソッドを実行します。
その下のeditTextResponseは、リクエストで得られた結果を表示するスペース。
次回はレスポンスボディとは別にヘッダも出してみよう。
こっそり、一番下にちっさくtextViewTimeというのがあります。
リクエストを取得するのにかかった時間を測定して、出力してみます。


というわけで、以下のようなコードを書きました。


```java:MainActivity.java
package com.example.hogehogehoge.testapp11;

import android.os.Bundle;
import android.support.v7.app.AppCompatActivity;
import android.util.Log;
import android.view.View;
import android.widget.Button;
import android.widget.EditText;
import android.widget.TextView;
import android.widget.Toast;

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.net.HttpURLConnection;
import java.net.URL;

public class MainActivity extends AppCompatActivity {

    TextView textViewUrl;
    EditText editTextUrl;
    Button buttonGet;
    EditText editTextResponse;
    TextView textViewTime;
    long startTime;
    long endTime;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        textViewUrl = (TextView)findViewById(R.id.textViewUrl);
        textViewTime = (TextView)findViewById(R.id.textViewTime);
        editTextUrl = (EditText)findViewById(R.id.editTextUrl);
        buttonGet = (Button)findViewById(R.id.buttonGet);
        textViewTime = (TextView)findViewById(R.id.textViewTime);
        editTextResponse = (EditText)findViewById(R.id.editTextResponse);

        editTextUrl.setText("http://自分のテストサーバ/get.php?target=test");
    }

    //ボタンクリックの動作確認用
    public void onButtonGetTest(View view) {
        Toast.makeText(this,"click test",Toast.LENGTH_SHORT).show();
    }

    public void onButtonGet(View view) {
        new Thread(new Runnable() {
            @Override
            public void run() {
                try {
                    URL url = new URL(editTextUrl.getText().toString());
                    // 処理開始時刻
                    startTime = System.currentTimeMillis();
                    HttpURLConnection con = (HttpURLConnection)url.openConnection();
                    final String str = InputStreamToString(con.getInputStream());
                    // 処理終了時刻
                    endTime = System.currentTimeMillis();
                    Log.d("HTTP", str);

                    runOnUiThread(new Runnable() {
                        @Override
                        public void run() {
                            editTextResponse.setText(String.valueOf(str));
                            textViewTime.setText("処理時間：" + (endTime - startTime) + "ms");
                        }
                    });
                } catch (Exception ex) {
                    System.out.println(ex);
                }
            }
        }).start();
    }

    // InputStream -> String
    static String InputStreamToString(InputStream is) throws IOException {
        BufferedReader br = new BufferedReader(new InputStreamReader(is));
        StringBuilder sb = new StringBuilder();
        String line;
        while ((line = br.readLine()) != null) {
            sb.append(line);
        }
        br.close();
        return sb.toString();
    }
}

```

##参考
[AndroidでHTTP通信（GETリクエスト）](http://qiita.com/yasumodev/items/a5cbac4278cd14c74899)
[別のスレッドからアプリのメインスレッドのUIを操作する](http://cuuma.publog.jp/archives/30332977.html)

##解説
アプリ起動時に、onCreateが実行され、その中で

```java

editTextUrl.setText("http://自分のテストサーバ/get.php?target=test");
```

が実行されて、editTextUrlに任意のURIがセットされる。
editTextなので、アプリから自分でいじることももちろんできる。

GETボタンが押されると、onClickプロパティで定義されたonButtonGetメソッドが実行される。
新しいスレッドを作成し、その中でURLオブジェクトを生成し、生成されたURLオブジェクトを使ってHttpUrlConnectionを実行。
得られた結果をstrにしまう。しまう際には自分で定義したInputStreamToStringメソッドを利用する。（参考ページ参照）
また、このHttpUrlConnection実行から結果をstrにしまうところまでを処理時間として時間を計測している（ここでいいんだろうか、この場合）。
いったん、得られた結果をLog.dを使ってコンソールに出してみる。

そのあと、メインスレッド上のUI操作が可能なrunOnUiThreadとかいう便利なメソッドを呼び出し、得られたレスポンスと計測した時間をUIにsetする。

※わかってないこと
ここにrunOnUiThreadおいてみたら、String strの前に勝手にfinalが付いた。
そもそもこのfinal修飾句？がよくわかってないのであとで調べる。

InputStreamToStringメソッドは写経。
中身を見るに、Input（レスポンスの中身のことかな）に入ってきたものを1行ずつ確認して、これが空になるまで返り値にappendし続けるみたいな感じだね。
これはまぁなんとなくわかる。

##ちなみに

ちなみに、このAPIではtargetクエリにtestをいれてリクエストすると、以下のレスポンス（json）が得られる。

```json
{"status":"true","res":"GET test success","explain":"GET test successed"}
```

別に深い意味はないです。自分でそうなるように実装しただけ。


##実行結果

アプリ起動

![2.png](https://qiita-image-store.s3.amazonaws.com/0/51774/6fff1eef-cd58-9b2b-3612-383be1139f51.png)

うん。想定通り、任意の（onCreateにハードコーディングされた）URIが挿入された状態で起動。
GETボタンを押して実行すると。

![3.png](https://qiita-image-store.s3.amazonaws.com/0/51774/75abf283-de0d-8632-2ffe-ac95acdb9c3d.png)

処理時間の部分がでかくなったせいか、結果表示部分が右にモコってズレたｗｗｗ



今日はここまで(´･ω･｀)