JSONとは
地図の住所情報や、天気の情報をインターネットから取得したい場合はJSONデータを扱います。
例えば、東京都庁についてのGoogle Maps Geocoding API 情報を取得したければ
を表示します。結果として、
{ "results" : [ { "address_components" : [ { "long_name" : "1", "short_name" : "1", "types" : [ "premise" ] }, { "long_name" : "8", "short_name" : "8", "types" : [ "political", "sublocality", "sublocality_level_4" ] }, -------略------------ { "long_name" : "日本", "short_name" : "JP", "types" : [ "country", "political" ] }, { "long_name" : "163-8001", "short_name" : "163-8001", "types" : [ "postal_code" ] } ], "formatted_address" : "日本、〒163-8001 東京都新宿区西新宿2丁目8−1", "geometry" : { "location" : { "lat" : 35.6896342, --------------略------------- "local_government_office", "point_of_interest" ] }, { "address_comp ----------- 略 ----------- "status" : "OK" }
となります。
この帰ってきたデータの形式がJSONであり、このデータをVolleyを使って解析し、Androidアプリで活用します。
AndroidでVolleyの実装
実装は簡単です。gradleに以下を追加するだけです。
implementation 'com.android.volley:volley:1.1.0'
古いgradleでは
compile 'com.android.volley:volley:1.1.0'
書き加えて、gradleを更新します。
ActivityのJavaで
JsonObjectRequest adReq
と試しに記述をして、問題なければ成功です。
また、インターネットにアクセスして情報を取得するアプリとなりますから
Manifestに以下を追記します。
<uses-permission android:name="android.permission.INTERNET" />
JSON解析を行うために次のクラスを追加します。
public class AppController extends Application { public static final String TAG = AppController.class.getSimpleName(); private RequestQueue mRequestQueue; private static AppController mInstance; @Override public void onCreate() { super.onCreate(); mInstance = this; } public static synchronized AppController getInstance() { return mInstance; } public RequestQueue getRequestQueue() { if (mRequestQueue == null) { mRequestQueue = Volley.newRequestQueue(getApplicationContext()); } return mRequestQueue; } public <T> void addToRequestQueue(Request<T> req) { req.setTag(TAG); getRequestQueue().add(req); } }
さらにこのAppControllerについて、Manifestに登録します。
<application android:name="***.***.jsonactivity.AppController" android:allowBackup="true" ---略--- > </application>
特に理屈を考えず、AppControllerとManifestの登録が必要だ、と覚えてしまって問題ありません。
準備のまとめ
gradleにVolleyを追加する
ManifestにINTERNETを追加
AppControllerクラスを追加
ManifestにAppControllerを設定
どれか一つ、意外と忘れてしまいたちなので忘れずに設定してください。
住所を取得する方法(formatted_address)
住所を取得する際、アドレスに日本語文字は使えませんので、URL用に文字をエンコードす必要があります。
東京都庁 → %E6%9D%B1%E4%BA%AC%E9%83%BD%E5%BA%81
といった具合の変換です。
変換方法は、
String placeString = "東京都庁"; String encodedResult; try{ encodedResult= URLEncoder.encode(placeString, "UTF-8"); }catch (Exception e){ encodedResult =""; }
となります。 try-catchが必要です。
続けてJSONの結果の言語を指定します。
Locale locale = Locale.getDefault(); String language = locale.getLanguage();
として、端末で使用している言語を取得します。
その上で取得用アドレスに言語を設定します。
String url = "https://maps.googleapis.com/maps/api/geocode/json?address=" +encodedResult+"&language="+language+"&key="+"YOUR_KEY";
Android、この地図JSONも共にgoogleですから、Localeで取得した言語とアドレスで指定する言語は同じで、このように設定することができます。
では実際に「formatted_address」を取得してみます。
{
"results" : [
{
"address_components" : [
{
"long_name" : "1",
--------------略-----------------
"types" : [ "postal_code" ]
}
],
"formatted_address" : "日本、〒163-8001 東京都新宿区西新宿2丁目8−1",
[]は配列、{はオブジェクト となります。
results配列の0個目、のformatted_addressを取得 するということになります。
String url = "https://maps.googleapis.com/maps/api/geocode/json?address=" +encodedResult+"&language="+language; JsonObjectRequest adReq = new JsonObjectRequest(Request.Method.GET, url, null, new Response.Listener <JSONObject>() { @Override public void onResponse(JSONObject response) { try { addressString = response.getJSONArray("results").getJSONObject(0).getString("formatted_address"); Log.d("Log0",addressString); } catch (JSONException e) { Log.d("Log0", "" + e); } } }, new Response.ErrorListener() { @Override public void onErrorResponse(VolleyError error) { VolleyLog.d("Log0", "Error: " + error.getMessage()); } } ); AppController.getInstance().addToRequestQueue(adReq);
とします。 addressStringは Activity冒頭で定義しておきます。
郵便番号を取得する方法(postal_code)
見てみると返されたJSONのpostal_codeは address_components の中にあります。
{ "results" : [ { "address_components" : [ { "long_name" : "1", "short_name" : "1", "types" : [ "premise" ] }, --------------略---------------- { "long_name" : "163-8001", "short_name" : "163-8001", "types" : [ "postal_code" ] } ], "formatted_address" : "日本、〒163-8001 東京都新宿区西新宿2丁目8−1",
階層を追ってみてみると
results配列の0個目のaddress_components配列のtypesがpostal_codeのlong_name、となります。
どう書くのかというと、
for (int i = 0; i < response.getJSONArray("results").getJSONObject(0) .getJSONArray("address_components").length(); i++) { typesString = response.getJSONArray("results").getJSONObject(0). getJSONArray("address_components").getJSONObject(i).getString("types"); longNameString = response.getJSONArray("results").getJSONObject(0). getJSONArray("address_components").getJSONObject(i).getString("long_name"); if (typesString.contains("postal_code")) { Log.d("Log0",longNameString); } }
少し面倒ですが、階層をわかりやすく。
address_componentsの中身を順にみて行って、typeがpostal_codeであるときの、long_nameを取得しています。
結果として、郵便番号が表示されます。
formatted_addressから郵便番号や国名を削除したい場合はこのpostal_codeya
countryを取得してreplaceして削除すれば良い。ということいなります。
addressString = addressString.replace(longNameString, "");
といった具合です。
実際はMAPを使うとよいので、いずれそのコードも。今回は使っておりません。
ソースコード
public class MainActivity extends AppCompatActivity { String addressString; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); Locale locale = Locale.getDefault(); String language = locale.getLanguage(); String placeString = "東京都庁"; String encodedResult; try{ encodedResult= URLEncoder.encode(placeString, "UTF-8"); }catch (Exception e){ encodedResult =""; } String url = "https://maps.googleapis.com/maps/api/geocode/json?address=" +encodedResult+"&language="+language; JsonObjectRequest adReq = new JsonObjectRequest(Request.Method.GET, url, null, new Response.Listener<JSONObject>() { @Override public void onResponse(JSONObject response) { try { addressString = response.getJSONArray("results").getJSONObject(0).getString("formatted_address"); Log.d("Log0",addressString); String longNameString; String typesString; for (int i = 0; i < response.getJSONArray("results").getJSONObject(0).getJSONArray("address_components").length(); i++) { typesString = response.getJSONArray("results").getJSONObject(0). getJSONArray("address_components").getJSONObject(i).getString("types"); longNameString = response.getJSONArray("results").getJSONObject(0). getJSONArray("address_components").getJSONObject(i).getString("long_name"); //typesに対応したlong_name if (typesString.contains("postal_code")) { addressString = addressString.replace(longNameString, ""); //以下はアドレスに含まれる余分な情報を削除する } if (typesString.contains("country")) { addressString = addressString.replace(longNameString, ""); } addressString = addressString.replace("〒 ", "");//郵便番号記号の削除 addressString = addressString.replace("、", ""); Log.d("Log0",addressString); } catch (JSONException e) { Log.d("Log0", "" + e); } } }, new Response.ErrorListener() { @Override public void onErrorResponse(VolleyError error) { VolleyLog.d("Log0", "Error: " + error.getMessage()); } } ); AppController.getInstance().addToRequestQueue(adReq); }
結果は
D/Log0: 日本、〒163-8001 東京都新宿区西新宿2丁目8−1
D/Log0: 東京都新宿区西新宿2丁目8−1
となるはずです。
googleMapと組み合わせて住所を取得する方法は次の機会に!