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

Cách hiển thị vị trí hiện tại trên Google Maps Android

Giới thiệu

Hướng dẫn tích hợp Google Maps SDK và Fused Location Provider để hiển thị vị trí hiện tại của người dùng trên bản đồ. Sử dụng API hiện đại (Play Services Location 21.x, Maps 18.x) thay vì code cũ deprecated.

Yêu cầu trước khi bắt đầu

  1. Google Cloud Project với Maps SDK for Android và Places API enabled.
  2. API Key với restriction (Android app + package name + SHA-1).
  3. minSdk 24+ (Android 7.0+).

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

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

Android Studio → File → New Project → Google Maps Activity (template có sẵn) hoặc Empty View Activity.

Bước 2: Thêm dependencies (build.gradle.kts)

dependencies {
    // Google Maps
    implementation("com.google.android.gms:play-services-maps:18.2.0")
    // Fused Location Provider (hiện đại, thay thế LocationManager cũ)
    implementation("com.google.android.gms:play-services-location:21.2.0")
    // Runtime permissions handling
    implementation("androidx.activity:activity-ktx:1.9.0")
    implementation("androidx.fragment:fragment-ktx:1.6.2")
}

Bước 3: Cấu hình AndroidManifest.xml

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

    <!-- Permissions -->
    <uses-permission android:name="android.permission.INTERNET" />
    <uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" />
    <uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION" />
    <!-- Foreground service location (Android 10+) nếu cần track liên tục -->
    <uses-permission android:name="android.permission.FOREGROUND_SERVICE_LOCATION" />

    <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/Theme.MapLocation">

        <!-- Google Maps API Key -->
        <meta-data
            android:name="com.google.android.geo.API_KEY"
            android:value="@string/google_maps_key" />

        <activity
            android:name=".MainActivity"
            android:exported="true">
            <intent-filter>
                <action android:name="android.intent.action.MAIN" />
                <category android:name="android.intent.category.LAUNCHER" />
            </intent-filter>
        </activity>
    </application>
</manifest>

Bước 4: Thêm API Key vào res/values/strings.xml

<resources>
    <string name="app_name">Map Location Demo</string>
    <!-- Thay YOUR_API_KEY bằng key thật từ Google Cloud Console -->
    <string name="google_maps_key" translatable="false">YOUR_API_KEY_HERE</string>
</resources>

Bước 5: Thiết kế giao diện (res/layout/activity_main.xml)

<?xml version="1.0" encoding="utf-8"?>
<FrameLayout 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"
    tools:context=".MainActivity">

    <fragment
        android:id="@+id/mapFragment"
        android:name="com.google.android.gms.maps.SupportMapFragment"
        android:layout_width="match_parent"
        android:layout_height="match_parent" />

    <!-- Loading indicator -->
    <ProgressBar
        android:id="@+id/progressBar"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_gravity="center"
        android:visibility="gone" />
</FrameLayout>

Bước 6: Code chính (MainActivity.kt - Kotlin khuyến nghị)

package com.example.maplocation

import android.Manifest
import android.content.pm.PackageManager
import android.location.Location
import android.os.Bundle
import android.widget.Toast
import androidx.appcompat.app.AppCompatActivity
import androidx.core.app.ActivityCompat
import androidx.core.content.ContextCompat
import androidx.lifecycle.lifecycleScope
import com.google.android.gms.location.FusedLocationProviderClient
import com.google.android.gms.location.LocationServices
import com.google.android.gms.location.Priority
import com.google.android.gms.maps.CameraUpdateFactory
import com.google.android.gms.maps.GoogleMap
import com.google.android.gms.maps.OnMapReadyCallback
import com.google.android.gms.maps.SupportMapFragment
import com.google.android.gms.maps.model.LatLng
import com.google.android.gms.maps.model.MarkerOptions
import com.google.android.gms.tasks.CancellationTokenSource
import kotlinx.coroutines.launch

class MainActivity : AppCompatActivity(), OnMapReadyCallback {

    private lateinit var map: GoogleMap
    private lateinit var fusedLocationClient: FusedLocationProviderClient
    private val cancellationTokenSource = CancellationTokenSource()

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_main)

        fusedLocationClient = LocationServices.getFusedLocationProviderClient(this)

        val mapFragment = supportFragmentManager.findFragmentById(R.id.mapFragment) as SupportMapFragment
        mapFragment.getMapAsync(this)
    }

    override fun onMapReady(googleMap: GoogleMap) {
        map = googleMap
        map.uiSettings.isMyLocationButtonEnabled = true
        map.uiSettings.isCompassEnabled = true
        
        // Yêu cầu permission và lấy vị trí
        requestLocationAndShow()
    }

    private fun requestLocationAndShow() {
        if (ContextCompat.checkSelfPermission(this, Manifest.permission.ACCESS_FINE_LOCATION)
            != PackageManager.PERMISSION_GRANTED) {
            // Request permission dùng ActivityResultContracts (API 33+)
            requestPermissionLauncher.launch(Manifest.permission.ACCESS_FINE_LOCATION)
        } else {
            getCurrentLocation()
        }
    }

    private fun getCurrentLocation() {
        binding.progressBar.visibility = View.VISIBLE
        
        // API hiện đại: getCurrentLocation với Priority
        fusedLocationClient.getCurrentLocation(Priority.PRIORITY_HIGH_ACCURACY, cancellationTokenSource.token)
            .addOnSuccessListener { location: Location? ->
                binding.progressBar.visibility = View.GONE
                location?.let { showLocationOnMap(it) }
                    ?: Toast.makeText(this, "Không lấy được vị trí", Toast.LENGTH_SHORT).show()
            }
            .addOnFailureListener { e ->
                binding.progressBar.visibility = View.GONE
                Toast.makeText(this, "Lỗi GPS: ${e.message}", Toast.LENGTH_SHORT).show()
            }
    }

    private fun showLocationOnMap(location: Location) {
        val latLng = LatLng(location.latitude, location.longitude)
        val markerOptions = MarkerOptions()
            .position(latLng)
            .title("Tôi ở đây!")
            .snippet("Lat: ${location.latitude}, Lng: ${location.longitude}")

        map.addMarker(markerOptions)
        map.animateCamera(CameraUpdateFactory.newLatLngZoom(latLng, 15f))
    }

    // ActivityResultContracts cho permission (API 33+)
    private val requestPermissionLauncher = registerForActivityResult(
        androidx.activity.result.contract.ActivityResultContracts.RequestPermission()
    ) { granted ->
        if (granted) getCurrentLocation()
        else Toast.makeText(this, "Cần quyền vị trí để hiển thị bản đồ", Toast.LENGTH_SHORT).show()
    }

    override fun onDestroy() {
        super.onDestroy()
        cancellationTokenSource.cancel()
    }
}

Lấy API Key từ Google Cloud Console

  1. Truy cập Google Cloud Console.
  2. Tạo project mới hoặc chọn project hiện có.
  3. Enable APIs: Maps SDK for Android, Places API (tùy chọn).
  4. Vào APIs & Services → Credentials → Create Credentials → API Key.
  5. Restrict key: Application restrictions → Android apps → Thêm package name + SHA-1 certificate fingerprint.
  6. Copy API Key vào strings.xml.

Lưu ý quan trọng

  • Không dùng getLastLocation() cũ - hay trả về null. Dùng getCurrentLocation() (Play Services Location 21+).
  • Xử lý permission runtime đúng cách với ActivityResultContracts.
  • Luôn cancel location request trong onDestroy() để tránh leak.
  • Test trên thiết bị thật (emulator thường không có GPS chính xác).
  • API Key phải restrict để tránh bị lạm dụng (quota, billing).