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と組み合わせて住所を取得する方法は次の機会に!