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

Cách lấy thông tin thành phố lân cận từ Network Provider trên Android

Giới thiệu

Lấy thông tin quận/huyện/thành phố lân cận (sub-admin area) từ vị trí mạng. Sử dụng address.getSubAdminArea() từ Geocoder. Phù hợp cho ứng dụng thời tiết, tin tức địa phương, tìm kiếm khu vực.

Triển khai

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

Android Studio → New Project → Empty Activity.

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

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout 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:orientation="vertical"
    android:padding="16dp"
    android:gravity="center"
    tools:context=".MainActivity">

    <TextView
        android:id="@+id/text"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:textSize="22sp"
        android:gravity="center"
        android:lineSpacingExtra="4dp"
        tools:text="Thông tin khu vực" />

</LinearLayout>

Bước 3: MainActivity.java

package com.example.myapplication;

import android.Manifest;
import android.content.pm.PackageManager;
import android.location.Address;
import android.location.Geocoder;
import android.location.Location;
import android.location.LocationManager;
import android.os.Build;
import android.os.Bundle;
import androidx.annotation.RequiresApi;
import androidx.core.app.ActivityCompat;
import androidx.appcompat.app.AppCompatActivity;
import android.widget.TextView;
import java.io.IOException;
import java.util.List;
import java.util.Locale;

public class MainActivity extends AppCompatActivity {
    TextView textView;
    Location location;
    List<Address> addresses;
    Geocoder geocoder;

    @RequiresApi(api = Build.VERSION_CODES.P)
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        textView = findViewById(R.id.text);

        LocationManager locationManager = (LocationManager) getSystemService(LOCATION_SERVICE);

        if (ActivityCompat.checkSelfPermission(this, Manifest.permission.ACCESS_FINE_LOCATION) != PackageManager.PERMISSION_GRANTED
                && ActivityCompat.checkSelfPermission(this, Manifest.permission.ACCESS_COARSE_LOCATION) != PackageManager.PERMISSION_GRANTED) {
            ActivityCompat.requestPermissions(this,
                    new String[]{Manifest.permission.ACCESS_FINE_LOCATION, Manifest.permission.ACCESS_COARSE_LOCATION}, 101);
        }

        location = locationManager.getLastKnownLocation(LocationManager.NETWORK_PROVIDER);
        geocoder = new Geocoder(this, Locale.getDefault());
    }

    @RequiresApi(api = Build.VERSION_CODES.O)
    @Override
    public void onRequestPermissionsResult(int requestCode, String[] permissions, int[] grantResults) {
        if (requestCode == 101 && grantResults.length > 0 && grantResults[0] == PackageManager.PERMISSION_GRANTED) {
            if (ActivityCompat.checkSelfPermission(this, Manifest.permission.ACCESS_FINE_LOCATION) != PackageManager.PERMISSION_GRANTED
                    && ActivityCompat.checkSelfPermission(this, Manifest.permission.ACCESS_COARSE_LOCATION) != PackageManager.PERMISSION_GRANTED) {
                return;
            }
            fetchAreaInfo();
        }
        super.onRequestPermissionsResult(requestCode, permissions, grantResults);
    }

    @RequiresApi(api = Build.VERSION_CODES.O)
    @Override
    protected void onResume() {
        super.onResume();
        if (ActivityCompat.checkSelfPermission(this, Manifest.permission.ACCESS_FINE_LOCATION) != PackageManager.PERMISSION_GRANTED
                && ActivityCompat.checkSelfPermission(this, Manifest.permission.ACCESS_COARSE_LOCATION) != PackageManager.PERMISSION_GRANTED) {
            return;
        }
        fetchAreaInfo();
    }

    private void fetchAreaInfo() {
        if (location == null) {
            textView.setText("Không có vị trí\nBật định vị và thử lại");
            return;
        }
        try {
            addresses = geocoder.getFromLocation(location.getLatitude(), location.getLongitude(), 3); // Lấy 3 kết quả
            if (addresses != null && !addresses.isEmpty()) {
                StringBuilder info = new StringBuilder();
                info.append("Vị trí: ").append(String.format("%.4f, %.4f", 
                    location.getLatitude(), location.getLongitude())).append("\n\n");
                
                for (int i = 0; i < addresses.size(); i++) {
                    Address addr = addresses.get(i);
                    info.append("Kết quả ").append(i + 1).append(":\n");
                    info.append("  Đầy đủ: ").append(addr.getAddressLine(0)).append("\n");
                    info.append("  Quận/Huyện (SubAdminArea): ").append(addr.getSubAdminArea() != null ? addr.getSubAdminArea() : "N/A").append("\n");
                    info.append("  Tỉnh/TP (AdminArea): ").append(addr.getAdminArea() != null ? addr.getAdminArea() : "N/A").append("\n");
                    info.append("  Phường/Xã (SubLocality): ").append(addr.getSubLocality() != null ? addr.getSubLocality() : "N/A").append("\n");
                    info.append("  Thành phố (Locality): ").append(addr.getLocality() != null ? addr.getLocality() : "N/A").append("\n\n");
                }
                textView.setText(info.toString());
            } else {
                textView.setText("Không tìm thấy thông tin khu vực");
            }
        } catch (IOException e) {
            e.printStackTrace();
            textView.setText("Lỗi: " + e.getMessage());
        }
    }
}

Bước 4: Manifest

<uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION" />
<uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" />
<uses-permission android:name="android.permission.INTERNET" />

Cấu trúc địa chỉ hành chính Việt Nam trong Geocoder

CấpPhương thức GeocoderVí dụ
Quốc giagetCountryName() / getCountryCode()Vietnam / VN
Tỉnh/Thành phốgetAdminArea()Hà Nội, Hồ Chí Minh, Đà Nẵng
Quận/Huyện/Thị xãgetSubAdminArea()Quận 1, Ba Vì, Sơn Trà
Phường/Xã/ThôngetSubLocality()Phường Bến Nghé, Xã Đông Xuân
Thành phố (cấp dưới)getLocality()Thường trùng AdminArea ở VN
Địa danh/Địa điểmgetFeatureName()Bến Thành Market, West Lake

Lưu ý quan trọng

  • getSubAdminArea() ở Việt Nam thường trả về Quận/Huyện
  • getAdminArea() trả về Tỉnh/Thành phố trực thuộc TW
  • Kết quả phụ thuộc vào dữ liệu Google Maps, vùng vắng có thể thiếu
  • Network Provider độ chính xác thấp → có thể trả về quận/huyện sai lân cận
  • Nên dùng FusedLocationProviderClient + Geocoder cho độ chính xác cao hơn

Mở rộng: Tìm thành phố lân cận thực sự

Nếu cần tìm các thành phố gần vị trí hiện tại (không phải quận/huyện chứa vị trí), cần dùng Reverse Geocoding với radius hoặc Places API:

// Ý tưởng: dùng Places API Nearby Search
// https://maps.googleapis.com/maps/api/place/nearbysearch/json?location=LAT,LNG&radius=50000&type=locality&key=API_KEY