258 Lab アプリ開発日記

Andorid,iOSアプリ開発してます。

【Android】ホットペッパーグルメAPIを利用して周辺の飲食店を表示する方法

どこ食べのバージョンアップ対応で現在地から飲食店の一覧を取得することがあったので備忘録📝

今回の実装内容

今回はリクルートWEBサービスのグルメサーチAPIを使用して、指定した緯度経度や条件から周辺の飲食店を取得してくる。🍜 APIの詳細は公式サイトをご覧ください🐶

webservice.recruit.co.jp

1. APIキーの取得

ホットペッパーWEBサービスからAPIキーの申請を行う。 申請方法はリクルートWEBサービス(上URL)にアクセスし、[新規登録]ボタンからユーザー登録すれば取得することができる。

2. 実装

APIキーが取得できたら実際に実装していく。

2.1 権限の追加

インターネットを使用するため、AndroidManifest.xmlに権限を追加する。

<uses-permission android:name="android.permission.INTERNET" />
2.2 ホットペッパーAPIのパラメータクラスを作成

パラメータのクラスを作成する。

public class HotPepperGourmetSearch {
    private Double lat; // 緯度
    private Double lng; // 経度
    private int lunch; // ランチ営業有無
    private int range; // 検索範囲距離
    private int midnight_meal; // // 23時以降食事OK
    private ArrayList<String> keywordList; // キーワードのリスト
    private ArrayList<String> genreCdList; // ジャンルのリスト

    public Double getLat() {
        return lat;
    }

    public void setLat(Double lat) {
        this.lat = lat;
    }

    public Double getLng() {
        return lng;
    }

    public void setLng(Double lng) {
        this.lng = lng;
    }

    public int getLunch() {
        return lunch;
    }

    public void setLunch(int lunch) {
        this.lunch = lunch;
    }

    public int getRange() {
        return range;
    }

    public void setRange(int range) {
        this.range = range;
    }

    public int getMidnight_meal() {
        return midnight_meal;
    }

    public void setMidnight_meal(int midnight_meal) {
        this.midnight_meal = midnight_meal;
    }

    public ArrayList<String> getGenreCdList() {
        return genreCdList;
    }

    public void setGenreCdList(ArrayList<String> genreCdList) {
        this.genreCdList = genreCdList;
    }

    public ArrayList<String> getKeywordList() {
        return keywordList;
    }

    public void setKeywordList(ArrayList<String> keywordList) {
        this.keywordList = keywordList;
    }
}
2.2 APIコール後の戻り値のクラスを作成

APIをコールしてから戻ってくる飲食店の情報を格納するクラスを作成する。

public class HotPepperGourmet {
    private String name; // 飲食店の名前
    private String address; // 住所
    private Double lat; // お店の緯度
    private Double lng; // お店の経度
    private String lunch; // ランチ有無
    private String url; // お店のURL
    private String id; // お店コード

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public String getAddress() {
        return address;
    }

    public void setAddress(String address) {
        this.address = address;
    }

    public Double getLat() {
        return lat;
    }

    public void setLat(Double lat) {
        this.lat = lat;
    }

    public Double getLng() {
        return lng;
    }

    public void setLng(Double lng) {
        this.lng = lng;
    }

    public String getLunch() {
        return lunch;
    }

    public void setLunch(String lunch) {
        this.lunch = lunch;
    }

    public String getUrl() {
        return url;
    }

    public void setUrl(String url) {
        this.url = url;
    }

    public String getId() {
        return id;
    }

    public void setId(String id) {
        this.id = id;
    }
}
2.3 APIを呼び出すクラスを作成

ActivityやFragmentからAPIをコールする処理を作成する。

    /**
     * ホットペッパーグルメAPIの呼び出し
     */
    public static void callHotPepperGourmetRestaurant(Activity activity, HotPepperGourmetSearch hotPepperGourmetSearch) {
        // URLの作成

        // ジャンルの切り取り
        StringBuilder genreSb = new StringBuilder();
        genreSb.append("&genre=");

        for (int i = 0; i < hotPepperGourmetSearch.getGenreCdList().size(); i++) {
            if (i > 0) {
                genreSb.append("&genre=");
            }

            String genreCd = hotPepperGourmetSearch.getGenreCdList().get(i);
            genreSb.append(genreCd);
        }

        // キーワードの切り取り
        StringBuilder keywordSb = new StringBuilder();
        keywordSb.append("&keyword=");

        for (int i = 0; i < hotPepperGourmetSearch.getKeywordList().size(); i++) {
            if (i > 0) {
                keywordSb.append("&keyword=");
            }

            String keyword = hotPepperGourmetSearch.getKeywordList().get(i);
            keywordSb.append(keyword);
        }

        // URLの生成
        StringBuilder urlStringBuilder = new StringBuilder();
        urlStringBuilder.append("http://webservice.recruit.co.jp/hotpepper/gourmet/v1/?key=");
        urlStringBuilder.append(API_KEY);
        urlStringBuilder.append(genreSb.toString()); // 飲食店のジャンル
        urlStringBuilder.append("&midnight_meal="); // 23時以降食事OK
        urlStringBuilder.append(hotPepperGourmetSearch.getMidnight_meal());
        urlStringBuilder.append(keywordSb.toString()); // キーワード
        urlStringBuilder.append("&lunch="); // ランチ営業
        urlStringBuilder.append(hotPepperGourmetSearch.getLunch());
        urlStringBuilder.append("&lat="); // 緯度
        urlStringBuilder.append(hotPepperGourmetSearch.getLat());
        urlStringBuilder.append("&lng="); // 経度
        urlStringBuilder.append(hotPepperGourmetSearch.getLng());
        urlStringBuilder.append("&range="); // 検索範囲距離
        urlStringBuilder.append(hotPepperGourmetSearch.getRange());
        urlStringBuilder.append("&count=100"); // 1ページあたりの取得数
        urlStringBuilder.append("&format=json") // レスポンス形式
        ; 

        URL url = null;

        try {
            url = new URL(urlStringBuilder.toString());
            // 非同期処理
            new RestaurantAsync(activity).execute(url).get(3000, TimeUnit.MILLISECONDS);
        } catch (MalformedURLException e) {
            e.printStackTrace();
        } catch (TimeoutException e) {
            e.printStackTrace();
            mToastMessage = "接続がタイムアウトになったため、お店の情報を取得できませんでした";
            Utils.toastMake(activity, mToastMessage);
        } catch (InterruptedException e) {
            e.printStackTrace();
        } catch (ExecutionException e) {
            e.printStackTrace();
        } finally {
            // プログレスバーを閉じる
            if (RestaurantAsync.sProgressDialog != null && RestaurantAsync.sProgressDialog.isShowing()) {
                RestaurantAsync.sProgressDialog.dismiss();
            }
        }
        Log.d(TAG, url.toString());
    }
2.4 非同期処理とJSONのパース

非同期処理でHTTP通信を行い、飲食店の情報を取得する。戻りの形式はJSON形式で指定したので、 非同期処理後に戻ってきたJSONをパースする。

public class RestaurantAsync extends AsyncTask<URL, Void, String> {

    private Activity mActivity;
    private StringBuffer mBuffer = new StringBuffer();

    private static final String TAG = "RestaurantAsync";

    public static ProgressDialog sProgressDialog;

    /**
     * コンストラクタ
     * @param activity
     */
    public RestaurantAsync(Activity activity) {
        mActivity = activity;
    }

    /**
     * 非同期処理の前処理
     */
    @Override
    protected void onPreExecute() {
        super.onPreExecute();
        // プログレスバーを表示する
        sProgressDialog = new ProgressDialog(mActivity);
        sProgressDialog.setCancelable(false); // キャンセルさせない
        sProgressDialog.setMessage("お店を検索中...");
        sProgressDialog.show();
    }

    /**
     * 非同期処理
     * @param url
     * @return
     */
    @Override
    protected String doInBackground(URL... url) {
        HttpURLConnection con = null;
        URL urls = url[0];

        try {
            con = (HttpURLConnection) urls.openConnection();
            // JSONダウンロード
            con.setRequestMethod("GET");
            // タイムアウト3秒
            con.setConnectTimeout(3000);
            con.setReadTimeout(3000);
            // 接続
            con.connect();

            // レスポンスコードの確認
            int resCd = con.getResponseCode();

            if (resCd != HttpURLConnection.HTTP_OK) {
                // 接続NG
                throw new IOException("HTTP responseCode:" + resCd);
            }

            InputStream inputStream = con.getInputStream();
            BufferedReader reader = new BufferedReader(new InputStreamReader(inputStream));
            String line;

            while (true) {
                line = reader.readLine();

                if (line == null) {
                    break;
                }

                mBuffer.append(line);
            }

            // クローズ
            inputStream.close();
            reader.close();

        } catch (IOException e) {
            e.printStackTrace();
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            // 接続をクローズ
            con.disconnect();
        }

        Log.d(TAG, mBuffer.toString());
        return mBuffer.toString();
    }

    /**
     * 非同期処理の後処理
     * @param result
     */
    @Override
    protected void onPostExecute(String result) {
        super.onPostExecute(result);

        try {
            // JSONをパースして各飲食店の情報を取得する
            JSONObject jsonObject = new JSONObject(result);
            JSONArray jsonArray = jsonObject.getJSONObject("results").getJSONArray("shop");
            ArrayList<HotPepperGourmet> hotPepperGourmetArray = new ArrayList<>();

            for (int i = 0; i < jsonArray.length(); i++) {
                HotPepperGourmet hotPepperGourmet = new HotPepperGourmet();
                JSONObject json = jsonArray.getJSONObject(i);
                String id = json.getString("id"); // お店ID
                String name = json.getString("name"); // 店名
                String address = json.getString("address"); // 住所
                Double lat = json.getDouble("lat"); // 緯度
                Double lng = json.getDouble("lng"); // 経度
                String lunch = json.getString("lunch"); //ランチありなし
                String url = json.getJSONObject("urls").getString("pc"); // URL

                Log.d(TAG, "お店ID:" + id);
                Log.d(TAG, "店名:" + name);
                Log.d(TAG, "住所:" + address);
                Log.d(TAG, "緯度:" + lat.toString());
                Log.d(TAG, "経度:" + lng.toString());
                Log.d(TAG, "ランチありなし:" + lunch);
                Log.d(TAG, "URL:" + url);

                hotPepperGourmet.setId(id);
                hotPepperGourmet.setName(name);
                hotPepperGourmet.setAddress(address);
                hotPepperGourmet.setLat(lat);
                hotPepperGourmet.setLng(lng);
                hotPepperGourmet.setLunch(lunch);
                hotPepperGourmet.setUrl(url);

                hotPepperGourmetArray.add(hotPepperGourmet);
            }

            if (mActivity instanceof ConfirmAsyncListener) {
                // コールバック処理
                ((ConfirmAsyncListener) mActivity).onRestaurantAsyncCallBack(hotPepperGourmetArray);
            }

        } catch (JSONException e) {
            e.printStackTrace();
        } finally {
            // プログレスバーを閉じる
            if (sProgressDialog != null && sProgressDialog.isShowing()) {
                sProgressDialog.dismiss();
            }
        }
    }

    interface ConfirmAsyncListener {
        void onRestaurantAsyncCallBack(ArrayList<HotPepperGourmet> hotPepperGourmetArray);
    }

}
2.5 画面からの呼び出し

Activiyからコールしてみる。今回はonCreateで呼び出してみる。 コール後、onRestaurantAsyncCallBackにて、取得結果を確認することができる。

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        
        // HotPepperグルメAPIの呼び出し
        HotPepperGourmetSearch hotPepperGourmetSearch = new HotPepperGourmetSearch();
        hotPepperGourmetSearch.setLat(mLat); // 画面でセットした緯度
        hotPepperGourmetSearch.setLng(mLng); // 画面でセットした経度
        hotPepperGourmetSearch.setLunch(mLunch); // 画面でセットしたランチ有無 
        hotPepperGourmetSearch.setRange(mRange); // 画面でセットした検索範囲距離
        hotPepperGourmetSearch.setGenreCdList(mGenreCdList); // 画面でセットしたジャンルのリスト
        hotPepperGourmetSearch.setMidnight_meal(mMidnight_meal); // 画面でセットした23時以降食事OK
        hotPepperGourmetSearch.setKeywordList(mKeywordList); // 画面でセットしたキーワードのリスト
        // APIコール 
       HotPepperUtils.callHotPepperGourmetRestaurant(MapsActivity.this, hotPepperGourmetSearch);
    }

    /**
     * ホットペッパーAPI呼び出し後のコールバック処理
     *
     * @param hotPepperGourmetArray
     */
    @Override
    public void onRestaurantAsyncCallBack(ArrayList<HotPepperGourmet> hotPepperGourmetArray) {
        // hotPepperGourmetArrayに飲食店の情報がセットされている
    }

では!