CodeZine(コードジン)

特集ページ一覧

AndroidアプリでのHTTPアクセスとJSONデータ処理

2020年版Androidの非同期処理 第2回

  • LINEで送る
  • このエントリーをはてなブックマークに追加
2020/12/10 11:00
目次

AndroidによるHTTPアクセス

 プロジェクトの準備ができたところで、まず、HTTPアクセスのコードを順に記述していきましょう。

asyncExecute()でURLを受け取れるように改造

 まず、リスト2の(1)で生成したURLを利用して非同期でWeb APIにアクセスするということは、asyncExecute()メソッドは、このURL文字列を受け取れるようにしなければなりません。その改造を行いましょう。これは、リスト4の太字のようになります。

[リスト4]MainActivity.java
private class ListItemClickListener implements AdapterView.OnItemClickListener {
    @Override
    public void onItemClick(…) {
        〜省略〜
        String url = WEATHERINFO_URL + "&q=" + q + "&appid=" + APP_ID;
        asyncExecute(url);  // (1)
    }
}

@UiThread
public void asyncExecute(final String url) {  // (2)
    Looper mainLooper = Looper.getMainLooper();
    Handler handler = HandlerCompat.createAsync(mainLooper);
    BackgroundTask backgroundTask = new BackgroundTask(handler, url);  // (3)
    ExecutorService executorService  = Executors.newSingleThreadExecutor();
    executorService.submit(backgroundTask);
}

 リスト4の(1)のように、あらかじめ生成しておいたurlを引数として渡します。

 次に、この引数を受け取れるように、asyncExecute()の引数としてURL文字列を定義します(リスト4の(2))。その際、前回紹介したように、スレッドセーフとするためにfinalを付与します。

 さらに、実際に非同期処理を行うのはBackgroundTaskクラスであるため、asyncExecute()内でそのBackgroundTaskをnewする際に、引数として受け取ったurlをそのまま渡しています。それが、リスト4の(3)です。

BackgroundTaskでurlを扱えるようにする

 ただし、このままではコンパイルエラーとなります。BackgroundTaskクラスでも、urlを受け取って扱えるように改造しましょう。これは、リスト5のようになります。

[リスト5]MainActivity.java
    private class BackgroundTask implements Runnable {
        private final Handler _handler;
        private final String _url;  // (1)

        public BackgroundTask(Handler handler, String url) {  // (2)
            _handler = handler;
            _url = url;  // (3)
        }
        〜省略〜
    }

 コード内容としては特に問題ないでしょう。コンストラクタでurlを受け取れるように引数をひとつ増やし(リスト5の(2))、それをフィールドに格納しています(リスト5(3))。注意点があるとすれば、リスト5の(1)のように、フィールドで定義するurlに対しては、finalを記述してスレッドセーフにする点です。

HTTPアクセスコード

 さて、準備が整いました。いよいよ、HTTPアクセスコードをBackgroundTaskのrun()メソッド内に記述していきましょう。これは、リスト6の内容になります。

[リスト6]MainActivity.java
public void run() {
    HttpURLConnection con = null;  // (a)
    InputStream is = null;  // (b)
    String result = "";  // (A)

    try {
        URL url = new URL(_url);  // (1)
        con = (HttpURLConnection) url.openConnection();  // (2)
        con.setRequestMethod("GET");  // (3)
        con.connect();  // (4)
        is = con.getInputStream();  // (5)

        result = is2String(is);  // (B)
    }
    catch(MalformedURLException ex) {
        Log.e(DEBUG_TAG, "URL変換失敗", ex);
    }
    catch(IOException ex) {
        Log.e(DEBUG_TAG, "通信失敗", ex);
    }
    finally {
        if(con != null) {  // (c)
            con.disconnect();  // (6)
        }
        if(is != null) {  // (d)
            try {
                is.close();
            }
            catch(IOException ex) {
                Log.e(DEBUG_TAG, "InputStream解放失敗", ex);
            }
        }
    }
    PostExecutor postExecutor = new PostExecutor(result); // (C)
    _handler.post(postExecutor);
}

 Androidで、というより、JavaでHTTPアクセス、特に、GETアクセスを行うソースコードパターンは、以下の6ステップです。

1. URL文字列からURLオブジェクトを生成する。

 リスト6の(1)が該当します。これは、接続先URL文字列をもとにURLクラスをnewします。リスト6の(1)では、リスト5においてフィールドで保持するようにした_urlをもとにnewしています。これで、Open WeatherのWeb APIサービスに接続できるようになります。

2. URLオブジェクトからHttpURLConnectionオブジェクトを取得する。

 リスト6の(2)が該当します。URLオブジェクトからHttpURLConnectionオブジェクトを取得するには、openConnection()メソッドを実行します。ただし、この戻り値は、URLConnectionですので、HttpURLConnectionにキャストします。

3. HTTPメソッドをGETに指定する。

 リスト6の(3)が該当します。これは、HttpURLConnectionのsetRequestMethod()を利用し、引数として「GET」を渡します。

4. GET接続を行う。

 リスト6の(4)が該当します。これは、HttpURLConnectionのconnect()を利用します。このメソッドを実行したとき、接続を行うだけでなく、レスポンスデータの取得まで行っています。そのため、HttpURLConnectionオブジェクト内部には、レスポンスデータが格納されています。

5. レスポンスデータを取得する。

 リスト6の(5)が該当します。4で説明したように、HTTPアクセス(接続)終了後には、レスポンスデータが格納されていますので、HttpURLConnectionのgetInputStream()メソッドを実行してレスポンスデータを取得します。このメソッド名の通り、戻り値は、InputStreamオブジェクトになる点に注意してください。

6. HttpURLConnectionオブジェクトを解放する。

 リスト6の(6)が該当します。このHttpURLConnectionオブジェクトの解放には、disconnect()メソッドを使います。ただし、HTTPアクセスには例外発生がつきものです。その場合でも確実に解放処理が行われるように、finallyブロックでdisconnect()を実行します。そのため、あらかじめ解放対象であるHttpURLConnectionオブジェクトをtryブロックの外側で宣言し(リスト6の(a))、その解放対象のHttpURLConnectionオブジェクトがnullかどうかをチェックした上でdisconnect()を実行します(リスト6の(c))。

 同様の考え方が、レスポンスデータを表すInputStreamオブジェクトにも当てはまりますので、リスト6の(b)で宣言を行い、finallyブロックの(d)でnullチェックの上、解放処理を行っています。

 このようにして取得したJSONデータを表すInputStreamオブジェクトを文字列に変換しているのがリスト6の(B)です。その際、あらかじめスケルトンプロジェクトに記述したis2String()メソッドが活躍します。戻り値であるresultは、目的のJSON文字列です。ただし、これもtryブロックの中の処理ですので、リスト6の(A)であらかじめ変数宣言をしておきます。

 最終的に、このJSON文字列であるresultをUIスレッド上で解析を行い、画面に表示させる必要があります。そのため、UIスレッドで処理を行う、PostExecutorをnewする際に渡すようにしています。それが、リスト6の(C)です。


  • LINEで送る
  • このエントリーをはてなブックマークに追加

バックナンバー

連載:2020年版Androidの非同期処理

著者プロフィール

  • WINGSプロジェクト 齊藤 新三(サイトウ シンゾウ)

    <WINGSプロジェクトについて> 有限会社 WINGSプロジェクトが運営する、テクニカル執筆コミュニティ(代表 山田祥寛)。主にWeb開発分野の書籍/記事執筆、翻訳、講演等を幅広く手がける。2018年11月時点での登録メンバは55名で、現在も執筆メンバを募集中。興味のある方は、どしどし応募頂きた...

  • 山田 祥寛(ヤマダ ヨシヒロ)

    静岡県榛原町生まれ。一橋大学経済学部卒業後、NECにてシステム企画業務に携わるが、2003年4月に念願かなってフリーライターに転身。Microsoft MVP for ASP/ASP.NET。執筆コミュニティ「WINGSプロジェクト」代表。 主な著書に「入門シリーズ(サーバサイドAjax/XM...

あなたにオススメ

All contents copyright © 2005-2021 Shoeisha Co., Ltd. All rights reserved. ver.1.5