WebAPIからJSON形式のデータを取得する|Android開発

   

AndroidアプリWebAPIを使ってJSON形式のデータを取得する方法です。
今回、サーバ側はCakePHP 3.6.11、WebAPIはGET通信でアクセスするものを作成しました。
また、テスト用のサーバはXAMPPを使っています。

サーバ側

JSON の有効化

config/routes.phpに以下(★の箇所)を追記します

Router::defaultRouteClass(DashedRoute::class);
Router::extensions(['json']); // ★

Controller の作成

WebAPIを実装するControllerを作成します。

WebApiController.php

<?php
namespace App\Controller;

use App\Controller\AppController;
use Cake\Event\Event;

class WebApiController extends AppController
{
    public function beforeFilter(Event $event)
    {
        parent::beforeFilter($event);
        $this->Auth->allow(['myFunction']);
    }

    public function myFunction()
    {
        $this->viewBuilder()->setClassName('Json');
        $arrays = array();
        $arrays[] = [
            'id' => 1,
            'name' => "User 001",
            'color' => "Red",
        ];
        $arrays[] = [
            'id' => 2,
            'name' => "User 002",
            'color' => "Blue",
        ];
        $arrays[] = [
            'id' => 3,
            'name' => "ユーザ 003",
            'color' => "Green",
        ];

        $this->set([
            'root' => $arrays,
            '_serialize' => ['root']
            ]);
        return ;
    }
}

ブラウザでの表示確認

ブラウザでhttp://サーバ名/cakePHPフォルダ/webapi/myFunction.jsonにアクセスします。

取得結果

CakePHP JSON結果

{
    "root": [
        {
            "id": 1,
            "name": "User 001",
            "color": "Red"
        },
        {
            "id": 2,
            "name": "User 002",
            "color": "Blue"
        },
        {
            "id": 3,
            "name": "\u30e6\u30fc\u30b6 003",
            "color": "Green"
        }
    ]
}
WebApiController.phpで17行目を有効にしている場合、http://サーバ名/cakePHPフォルダ/webapi/myFunctionでもアクセス可能になります。

Androidアプリ側

AsyncTask を使ってHttpアクセスを行う

非同期でデータを取得するため、AsyncTaskを継承したクラスでHttpアクセスを行います。受信データはJSONの文字列です。
取得が終わったら(onPostExecute)、呼び出し元(ResponseListener)へコールバックで通知します。

import android.os.AsyncTask;
import android.util.Log;

import org.apache.commons.lang3.StringUtils;

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

public class GetContentsAsyncTask extends AsyncTask<URL, Void, String> {
    private static final String TAG = "GetContentsAsyncTask";

    public interface ResponseListener {
        void onResponseDataReceived(String responseData);
    }

    private ResponseListener mListener;

    public GetContentsAsyncTask(ResponseListener listener) {
        if (listener == null) {
            listener = new ResponseListener() {
                @Override
                public void onResponseDataReceived(String responseData) {
                }
            };
        }
        mListener = listener;
    }

    @Override
    protected String doInBackground(URL... urls) {
        HttpURLConnection connection = null;
        try {
            connection = (HttpURLConnection) urls[0].openConnection();
            connection.setRequestMethod("GET");
            connection.addRequestProperty("User-agent", "Android");
            connection.addRequestProperty("Accept-Language", Locale.getDefault().toString());
            // リダイレクトなし.
            connection.setInstanceFollowRedirects(false);
            // データ入力用.
            connection.setDoInput(true);
            connection.setDoOutput(false);
            // 接続タイムアウト. 20sec.
            connection.setConnectTimeout(20000);
            // 読み取りタイムアウト. 30sec.
            connection.setReadTimeout(30000);
            connection.connect();

            // get Response.
            StringBuilder responseBuilder = new StringBuilder();
            InputStream iStream = null;
            BufferedReader reader = null;
            try {
                iStream = connection.getInputStream();
                String line;
                reader = new BufferedReader(new InputStreamReader(iStream, "UTF-8"));
                while ((line = reader.readLine()) != null) {
                    responseBuilder.append(line);
                }
            } catch (IOException e) {
                e.printStackTrace();
            } finally {
                if (!closeBufferedReader(reader)) {
                    closeInputStream(iStream);
                }
            }

            int statusCode = connection.getResponseCode();
            Log.i(TAG, urls[0] + " > statusCode=" + statusCode);
            return responseBuilder.toString();

        } catch (IOException e) {
            e.printStackTrace();
            Log.e(TAG, "HttpURLConnection method is error.");
            return StringUtils.EMPTY;
        } finally {
            if (connection != null) {
                connection.disconnect();
            }
        }
    }

    @Override
    protected void onPostExecute(String responseData) {
        mListener.onResponseDataReceived(responseData);
    }

    private static boolean closeBufferedReader(BufferedReader reader) {
        if (reader == null) {
            return false;
        }
        try {
            reader.close();
            return true;
        } catch (IOException e) {
            e.printStackTrace();
            return false;
        }
    }

    private static void closeInputStream(InputStream stream) {
        if (stream == null) {
            return;
        }
        try {
            stream.close();
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
}

呼び出し側Activity

JSONObjectクラスを使うことで、簡単にデータを参照できます。

import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;
import android.util.Log;
import android.view.View;

import org.apache.commons.lang3.StringUtils;
import org.json.JSONArray;
import org.json.JSONException;
import org.json.JSONObject;

import java.net.MalformedURLException;
import java.net.URL;

public class GetWebApiActivity extends AppCompatActivity
        implements GetContentsAsyncTask.ResponseListener {
    private static final String TAG = "GetWebApiActivity";

    private GetContentsAsyncTask mHttpTask;

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

        getServerData();
    }

    public void getServerData() {
        try {
            URL url = new URL("http://サーバ名/cakePHPフォルダ/webapi/myFunction.json");
            mHttpTask = new GetContentsAsyncTask(this);
            mHttpTask.execute(url);
        } catch (MalformedURLException e) {
            e.printStackTrace();
            onResponseDataReceived(StringUtils.EMPTY);
        }
    }

    @Override
    public void onResponseDataReceived(String responseData) {
        if (StringUtils.isEmpty(responseData)) {
            finish();
            return;
        }

        try {
            JSONObject json = new JSONObject(responseData);
            JSONArray lines = json.getJSONArray("root");
            for (int i = 0; i < lines.length(); i++) {
                JSONObject item = lines.getJSONObject(i);
                Log.i(TAG, item.getString("id")  + ", " + item.getString("name") + ", " + item.getString("color"));
            }
        } catch (JSONException e) {
            e.printStackTrace();
            finish();
        }
    }
}

実行時の出力ログ

I/GetWebApiActivity: 1, User 001, Red
I/GetWebApiActivity: 2, User 002, Blue
I/GetWebApiActivity: 3, ユーザ 003, Green

 - Android , , ,