Android
 Computer >> コンピューター >  >> プログラミング >> Android

Androidで住所から緯度・経度を取得する方法【Geocoderクラスの使い方を徹底解説】

この記事では、Androidアプリで入力された住所文字列から緯度(Latitude)と経度(Longitude)を取得する方法を解説します。Android標準のGeocoderクラスを利用することで、Google Maps APIキーなしでもジオコーディング(住所→座標変換)を実現できます。

実際に動作するサンプルアプリを題材に、レイアウトXML、Activity、Geocoder処理クラス、マニフェスト設定まで、ステップごとに丁寧に見ていきましょう。

全体の仕組み

本サンプルの処理の流れは以下の通りです。

  1. ユーザーがEditTextに住所を入力する
  2. ボタンをタップすると、バックグラウンドスレッドでGeocoderが住所を座標に変換する
  3. Handlerを通じて結果をUIスレッドに返し、TextViewに緯度・経度を表示する

なお、ネットワーク通信を伴うため、Geocoderの処理は必ずメインスレッド以外で実行する必要があります。このサンプルではThreadとHandlerを組み合わせて対応しています。

ステップ1:新規プロジェクトを作成する

まずAndroid Studioで新しいプロジェクトを作成します。メニューから「File」→「New Project」を選択し、必要な項目をすべて入力してプロジェクトを作成してください。テンプレートは「Empty Activity」で問題ありません。

ステップ2:レイアウトファイル(activity_main.xml)を作成する

次に、res/layout/activity_main.xmlに以下のコードを追加します。住所入力用のEditText、「Show Lat/Long」ボタン、結果表示用のTextViewを配置したシンプルな構成です。

<RelativeLayout
    xmlns:android="https://schemas.android.com/apk/res/android"
    xmlns:tools="https://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:padding="16sp"
    tools:context=".MainActivity">
    <TextView
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="Enter Address"
        android:id="@+id/textViewAddress"
        android:textAppearance="?android:attr/textAppearanceMedium"
        android:layout_alignParentStart="true" />
    <EditText
        android:layout_width="fill_parent"
        android:layout_height="wrap_content"
        android:id="@+id/editTextAddress"
        android:layout_alignParentTop="true"
        android:layout_toEndOf="@+id/textViewAddress"
        android:singleLine="true"
        android:text="" />
    <Button
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="Show Lat/Long"
        android:id="@+id/addressButton"
        android:layout_below="@+id/textViewAddress"
        android:layout_toEndOf="@+id/textViewAddress"
        android:layout_marginTop="50dp" />
    <TextView
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:textAppearance="?android:attr/textAppearanceLarge"
        android:text=""
        android:id="@+id/latLongTV"
        android:layout_centerVertical="true"
        android:layout_toEndOf="@+id/textViewAddress" />
</RelativeLayout>

ステップ3:MainActivity.javaを実装する

src/MainActivity.javaに以下のコードを追加します。ボタンがクリックされると、入力された住所をGeoCodingLocationクラスに渡し、結果はHandler(GeoCoderHandler)経由でTextViewに反映されます。

import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;
import android.os.Handler;
import android.os.Message;
import android.view.View;
import android.widget.Button;
import android.widget.EditText;
import android.widget.TextView;
public class MainActivity extends AppCompatActivity {
    Button addressButton;
    TextView textViewAddress;
    TextView textViewLatLong;
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        textViewAddress = findViewById(R.id.textViewAddress);
        textViewLatLong = findViewById(R.id.latLongTV);
        addressButton = findViewById(R.id.addressButton);
        addressButton.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View arg0) {
                EditText editText = findViewById(R.id.editTextAddress);
                String address = editText.getText().toString();
                GeoCodingLocation locationAddress = new GeoCodingLocation();
                locationAddress.getAddressFromLocation(address, getApplicationContext(), new
                    GeoCoderHandler());
            }
        });
    }
    private class GeoCoderHandler extends Handler {
        @Override
        public void handleMessage(Message message) {
            String locationAddress;
            switch (message.what) {
                case 1:
                    Bundle bundle = message.getData();
                    locationAddress = bundle.getString("address");
                break;
                default:
                locationAddress = null;
            }
            textViewLatLong.setText(locationAddress);
        }
    }
}

ステップ4:Geocoder処理クラス(GeoCodeLocation.java)を作成する

続いて、Javaクラス「GeoCodeLocation.java」を新規作成し、以下のコードを追加します。ここが中核となる処理です。Geocoder.getFromLocationName()メソッドに住所文字列を渡すことで、対応する緯度・経度を取得できます。

import android.content.Context;
import android.location.Address;
import android.location.Geocoder;
import android.os.Bundle;
import android.os.Handler;
import android.os.Message;
import android.util.Log;
import java.io.IOException;
import java.util.List;
import java.util.Locale;
class GeoCodeLocation {
    private static final String TAG = "GeoCodeLocation";
    public static void getAddressFromLocation(final String
    locationAddress,
    final Context
    context, final Handler handler) {
        Thread thread = new Thread() {
            @Override
            public void run() {
                Geocoder geocoder = new Geocoder(context,
                Locale.getDefault());
                String result = null;
                try {
                    List addressList = geocoder.getFromLocationName(locationAddress, 1);
                    if (addressList != null && addressList.size() > 0) {
                        Address address = (Address)
                            addressList.get(0);
                        StringBuilder sb = new StringBuilder();
                        sb.append(address.getLatitude()).append("\n");
                        sb.append(address.getLongitude()).append("\n");
                        result = sb.toString();
                    }
                } catch (IOException e) {
                    Log.e(TAG, "Unable to connect to Geocoder", e);
                } finally {
                    Message message = Message.obtain();
                    message.setTarget(handler);
                    if (result != null) {
                        message.what = 1;
                        Bundle bundle = new Bundle();
                        result = "Address: " + locationAddress +
                            "\n\nLatitude and Longitude
                            :\n" + result;
                        bundle.putString("address", result);
                        message.setData(bundle);
                    } else {
                        message.what = 1;
                        Bundle bundle = new Bundle();
                        result = "Address: " + locationAddress +
                            "\n Unable to get Latitude and
                            Longitude for this address location.";
                        bundle.putString("address", result);
                        message.setData(bundle);
                    }
                    message.sendToTarget();
                }
            }
        };
        thread.start();
    }
}

ポイントとして、getFromLocationName()の第2引数は取得する結果の最大件数です。ここでは先頭の1件のみを取得しています。また、Geocoderはデバイスのネットワーク接続に依存するため、IOExceptionのハンドリングを忘れないようにしましょう。

ステップ5:AndroidManifest.xmlにパーミッションを追加する

最後に、androidManifest.xmlに以下のコードを追加します。位置情報の利用にはACCESS_FINE_LOCATION、Geocoderによるオンライン検索にはINTERNETパーミッションが必要です。

<?xml version="1.0" encoding="utf-8"?>
<manifest
    xmlns:android="https://schemas.android.com/apk/res/android"
    package="app.com.sample">
    <uses-permission
        android:name="android.permission.ACCESS_FINE_LOCATION" />
    <uses-permission
        android:name="android.permission.INTERNET" />
    <application
        android:allowBackup="true"
        android:icon="@mipmap/ic_launcher"
        android:label="@string/app_name"
        android:roundIcon="@mipmap/ic_launcher_round"
        android:supportsRtl="true"
        android:theme="@style/AppTheme">
        <activity android:name=".MainActivity">
            <intent-filter>
                <action
                    android:name="android.intent.action.MAIN" />
                <category
                    android:name="android.intent.category.LAUNCHER" />
            </intent-filter>
        </activity>
    </application>
</manifest>

アプリを実行して動作を確認する

それでは、実際にアプリを起動して動作を確認してみましょう。実機のAndroidスマートフォンをPCにUSB接続している前提で進めます。

Android Studioからアプリを実行するには、プロジェクト内のアクティビティファイルをいずれか開き、ツールバーの「Run」アイコンをクリックします。デバイス選択ダイアログが表示されるので、接続したモバイルデバイスを選択してください。

アプリが起動したら、住所を入力して「Show Lat/Long」ボタンをタップします。正常に動作していれば、画面に入力した住所に対応する緯度と経度が表示されます。

Androidで住所から緯度・経度を取得する方法【Geocoderクラスの使い方を徹底解説】

Androidで住所から緯度・経度を取得する方法【Geocoderクラスの使い方を徹底解説】

まとめと補足

今回は、AndroidのGeocoderクラスを使って住所から緯度・経度を取得する方法を紹介しました。APIキーの登録が不要で手軽に使えるのが魅力ですが、以下の点には注意が必要です。

  • Geocoderはバックグラウンドサービスを利用するため、端末によっては利用できない場合があります(Geocoder.isPresent()で事前チェック可能)。
  • より高精度な位置情報や継続的な位置追跡が必要な場合は、Google Play ServicesのFusedLocationProviderClientの利用も検討しましょう。
  • 逆ジオコーディング(座標→住所)もgetFromLocation()メソッドで同様に実装できます。

地図連携アプリや配送管理アプリなど、位置情報を扱う開発の基礎として、ぜひ参考にしてください。

  1. AndroidスマホでAirTagを検出する方法|紛失タグの見つけ方を徹底解説

    Appleの「AirTag」は、鍵や財布、バッグなど、あらゆる持ち物の位置を追跡できる便利なアイテムとして近年急速に普及しています。しかし、その利便性の裏側では、知らないうちに自分の所持品へ取り付けられ、居場所を監視される「ストーカー行為」への懸念も高まっています。特にAndroidユーザーにとっては、iPhoneと比べて検知の仕組みが異なるため、注意が必要です。iPhoneやiPadをお使いの方なら、他人のAirTagが自分と一緒に移動している場合、デバイスに自動的にアラートが表示されます。ところがAndroidユーザーの場合、同じようにはいかず、いくつかの手順を踏まなければ、自分の持ち物に

  2. Windows 11でIPアドレスを確認する方法|コマンドプロンプトと設定アプリの手順

    インターネット接続に不具合が生じたとき、さまざまな対処法を試す中で、自分のPCのIPアドレスを把握しておくと意外と役立ちます。 IPアドレス(Internet Protocol Address)とは、インターネット上でデバイスを識別するための一意な数値アドレスのことです。機械にとっての「郵便番号」と考えると分かりやすいでしょう。現実世界で郵便番号が住所を特定するように、IPアドレスはコンピューターの場所を示し、デバイス同士がお互いを見つけて通信できるようにしています。 Windows 11でIPアドレスを確認する方法は複数あります。まずは最もシンプルな方法である「コマンドプロンプト」を使う