Computer >> บทช่วยสอนคอมพิวเตอร์ >  >> การเขียนโปรแกรม >> Android

วิธีใช้ Location API ติดตามตำแหน่งปัจจุบันใน Android Kotlin

บทนำ

ตัวอย่างนี้แสดงวิธีใช้ FusedLocationProviderClient (Google Play Services Location API) เพื่อดึงตำแหน่งปัจจุบันและแสดงบน Google Maps

ขั้นตอนที่ 1: สร้างโปรเจกต์

สร้างโปรเจกต์ Android ใหม่ เลือก Template "Google Maps Activity" หรือเพิ่ม Dependencies เอง

ขั้นตอนที่ 2: Dependencies (build.gradle)

dependencies {
    implementation 'com.google.android.gms:play-services-maps:18.2.0'
    implementation 'com.google.android.gms:play-services-location:21.0.1'
}

ขั้นตอนที่ 3: Layout (activity_maps.xml)

<?xml version="1.0" encoding="utf-8"?>
<fragment xmlns:android="https://schemas.android.com/apk/res/android"
    xmlns:tools="https://schemas.android.com/tools"
    android:id="@+id/map"
    android:name="com.google.android.gms.maps.SupportMapFragment"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    tools:context=".MapsActivity" />

ขั้นตอนที่ 4: MapsActivity.kt

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 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

class MapsActivity : AppCompatActivity(), OnMapReadyCallback {
    private lateinit var mMap: GoogleMap
    private lateinit var fusedLocationClient: FusedLocationProviderClient
    private val permissionRequestCode = 1001
    private val cancellationTokenSource = CancellationTokenSource()

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

        fusedLocationClient = LocationServices.getFusedLocationProviderClient(this)

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

    override fun onMapReady(googleMap: GoogleMap) {
        mMap = googleMap
        mMap.uiSettings.isMyLocationButtonEnabled = true
        mMap.uiSettings.isCompassEnabled = true
        
        enableMyLocation()
    }

    private fun enableMyLocation() {
        if (ActivityCompat.checkSelfPermission(this, Manifest.permission.ACCESS_FINE_LOCATION) 
            != PackageManager.PERMISSION_GRANTED) {
            ActivityCompat.requestPermissions(this, 
                arrayOf(Manifest.permission.ACCESS_FINE_LOCATION), permissionRequestCode)
            return
        }
        
        mMap.isMyLocationEnabled = true
        getCurrentLocation()
    }

    private fun getCurrentLocation() {
        if (ActivityCompat.checkSelfPermission(this, Manifest.permission.ACCESS_FINE_LOCATION) 
            != PackageManager.PERMISSION_GRANTED) return

        // ใช้ getCurrentLocation() แทน lastLocation (Deprecated ใน API ใหม่)
        fusedLocationClient.getCurrentLocation(Priority.PRIORITY_HIGH_ACCURACY, cancellationTokenSource.token)
            .addOnSuccessListener { location: Location? ->
                location?.let {
                    val currentLatLng = LatLng(it.latitude, it.longitude)
                    mMap.addMarker(MarkerOptions()
                        .position(currentLatLng)
                        .title("My Current Location")
                        .snippet("Lat: ${it.latitude}, Lng: ${it.longitude}"))
                    
                    mMap.animateCamera(CameraUpdateFactory.newLatLngZoom(currentLatLng, 15f))
                    Toast.makeText(this, "Location found!", Toast.LENGTH_SHORT).show()
                } ?: run {
                    Toast.makeText(this, "Location unavailable", Toast.LENGTH_SHORT).show()
                }
            }
            .addOnFailureListener { e ->
                Toast.makeText(this, "Error: ${e.message}", Toast.LENGTH_SHORT).show()
            }
    }

    override fun onRequestPermissionsResult(requestCode: Int, permissions: Array, grantResults: IntArray) {
        super.onRequestPermissionsResult(requestCode, permissions, grantResults)
        if (requestCode == permissionRequestCode && grantResults.isNotEmpty() 
            && grantResults[0] == PackageManager.PERMISSION_GRANTED) {
            enableMyLocation()
        } else {
            Toast.makeText(this, "Location permission required", Toast.LENGTH_LONG).show()
        }
    }

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

ขั้นตอนที่ 5: ขอ Google Maps API Key

  1. เข้า Google Cloud Console
  2. เปิดใช้งาน Maps SDK for Android และ Places API (ถ้าต้องการ)
  3. สร้าง API Key → จำกัดด้วย Package name + SHA-1

ขั้นตอนที่ 6: Manifest

<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="https://schemas.android.com/apk/res/android"
    package="com.example.locationdemo">
    
    <uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" />
    <uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION" />
    <uses-permission android:name="android.permission.INTERNET" />
    <uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
    
    <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">
        
        <meta-data
            android:name="com.google.android.geo.API_KEY"
            android:value="YOUR_API_KEY_HERE" />
        
        <activity android:name=".MapsActivity">
            <intent-filter>
                <action android:name="android.intent.action.MAIN" />
                <category android:name="android.intent.category.LAUNCHER" />
            </intent-filter>
        </activity>
    </application>
</manifest>

Location Priority Options

Priorityความแม่นยำการใช้พลังงานเหมาะสำหรับ
PRIORITY_HIGH_ACCURACY~10 เมตร (GPS)สูงNavigation, Tracking
PRIORITY_BALANCED_POWER_ACCURACY~100 เมตร (WiFi/Cell)ปานกลางGeneral use
PRIORITY_LOW_POWER~10 กม. (Cell tower)ต่ำWeather, Regional info
PRIORITY_NO_POWERPassive (รับจากแอปอื่น)ไม่ใช้เพิ่มBackground monitoring

Location Updates แบบต่อเนื่อง (Real-time Tracking)

val locationRequest = LocationRequest.create().apply {
    interval = 5000 // 5 วินาที
    fastestInterval = 2000
    priority = Priority.PRIORITY_HIGH_ACCURACY
}

val locationCallback = object : LocationCallback() {
    override fun onLocationResult(locationResult: LocationResult) {
        locationResult.lastLocation?.let { location ->
            // อัปเดต Marker, Camera
            val latLng = LatLng(location.latitude, location.longitude)
            // ...
        }
    }
}

fusedLocationClient.requestLocationUpdates(locationRequest, locationCallback, Looper.getMainLooper())

// หยุดเมื่อไม่ใช้
fusedLocationClient.removeLocationUpdates(locationCallback)