Computer >> Hướng Dẫn Máy Tính >  >> Lập Trình >> Android

Cách lấy vĩ độ và kinh độ từ địa chỉ trong Android (Geocoding)

Hướng dẫn này trình bày cách chuyển đổi địa chỉ văn bản (địa chỉ đường, tên địa điểm) thành tọa độ địa lý (Latitude/Longitude) sử dụng lớp Geocoder trong Android. Quá trình này gọi là Geocoding (ngược lại là Reverse Geocoding: từ tọa độ ra địa chỉ).

Các bước thực hiện

Bước 1: Tạo dự án mới

Mở Android Studio, chọn File → New Project và điền thông tin cần thiết.

Bước 2: Layout (res/layout/activity_main.xml)

<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="Nhập địa chỉ"
        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="Hiển thị Vĩ độ/Kinh độ"
        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>

Bước 3: MainActivity (src/MainActivity.java)

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(v -> {
            EditText editText = findViewById(R.id.editTextAddress);
            String address = editText.getText().toString().trim();

            if (address.isEmpty()) {
                textViewLatLong.setText("Vui lòng nhập địa chỉ");
                return;
            }

            GeoCodeLocation locationAddress = new GeoCodeLocation();
            locationAddress.getAddressFromLocation(address, getApplicationContext(), new GeoCoderHandler());
        });
    }

    // Handler nhận kết quả từ background thread
    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);
        }
    }
}

Bước 4: Lớp GeoCodeLocation (GeoCodeLocation.java)

Tạo file Java class mới:

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;

public class GeoCodeLocation {
    private static final String TAG = "GeoCodeLocation";

    public static void getAddressFromLocation(final String locationAddress,
                                              final Context context,
                                              final Handler handler) {
        // Chạy trên background thread vì Geocoder làm network I/O
        new Thread(() -> {
            Geocoder geocoder = new Geocoder(context, Locale.getDefault());
            String result = null;

            try {
                // Tìm tối đa 1 kết quả
                List<Address> addressList = geocoder.getFromLocationName(locationAddress, 1);

                if (addressList != null && !addressList.isEmpty()) {
                    Address address = addressList.get(0);
                    StringBuilder sb = new StringBuilder();
                    sb.append("Địa chỉ: ").append(locationAddress).append("\n\n");
                    sb.append("Vĩ độ: ").append(address.getLatitude()).append("\n");
                    sb.append("Kinh độ: ").append(address.getLongitude()).append("\n");
                    result = sb.toString();
                }
            } catch (IOException e) {
                Log.e(TAG, "Không thể kết nối Geocoder", e);
            } finally {
                Message message = Message.obtain();
                message.setTarget(handler);

                if (result != null) {
                    message.what = 1;
                    Bundle bundle = new Bundle();
                    bundle.putString("address", result);
                    message.setData(bundle);
                } else {
                    message.what = 1;
                    Bundle bundle = new Bundle();
                    bundle.putString("address",
                            "Địa chỉ: " + locationAddress + "\n Không thể lấy tọa độ cho địa chỉ này.");
                    message.setData(bundle);
                }
                message.sendToTarget();
            }
        }).start();
    }
}

Bước 5: Cấu hình quyền và Manifest (AndroidManifest.xml)

<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="https://schemas.android.com/apk/res/android"
    package="app.com.sample">

    <!-- Quyền cần thiết cho Geocoder -->
    <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>

Chạy ứng dụng

Kết nối thiết bị, nhấn Run. Nhập địa chỉ (ví dụ: "Hà Nội, Việt Nam" hoặc "1600 Amphitheatre Parkway, Mountain View, CA"), nhấn nút - ứng dụng sẽ hiển thị vĩ độ và kinh độ.

Cách lấy vĩ độ và kinh độ từ địa chỉ trong Android (Geocoding) Cách lấy vĩ độ và kinh độ từ địa chỉ trong Android (Geocoding)

Lưu ý quan trọng

  • Geocoder cần kết nối Internet (trừ một số thiết bị có dữ liệu offline)
  • Rate limit: Google giới hạn số request/ngày. Không lạm dụng trong vòng lặp
  • Locale: Kết quả phụ thuộc vào Locale.getDefault(). Có thể truyền new Locale("vi", "VN") cho tiếng Việt
  • isPresent(): Kiểm tra Geocoder.isPresent() trước khi dùng - một số thiết bị không có backend geocoding
  • Reverse Geocoding: Dùng geocoder.getFromLocation(lat, lng, maxResults) để từ tọa độ ra địa chỉ

Thay thế hiện đại

Để mạnh mẽ hơn, hãy dùng Google Maps Geocoding API (REST API, cần API Key, trả về JSON chi tiết hơn, hỗ trợ place_id, bounds, component filtering) hoặc Places SDK.