Menerima update lokasi berkala

Jika aplikasi Anda dapat terus melacak lokasi, hal itu dapat memberikan informasi yang lebih relevan kepada pengguna. Misalnya, jika aplikasi Anda membantu pengguna menemukan jalannya saat berjalan atau mengemudi, atau jika aplikasi Anda melacak lokasi aset, aplikasi perlu mendapatkan lokasi perangkat secara berkala. Selain lokasi geografis (lintang dan bujur), Anda mungkin ingin memberikan informasi lebih lanjut kepada pengguna seperti arah (arah pergerakan horizontal), ketinggian, atau kecepatan perangkat. Informasi ini dan lainnya tersedia di objek Location yang dapat diambil aplikasi Anda dari penyedia lokasi fusi.

Selagi Anda bisa mendapatkan lokasi perangkat dengan getLastLocation(), seperti yang diilustrasikan dalam tutorial mengenai Mendapatkan Lokasi Terakhir yang Diketahui, pendekatan langsung lainnya adalah meminta update berkala dari penyedia lokasi fusi. Sebagai respons atas hal tersebut, API mengupdate aplikasi Anda secara berkala dengan lokasi terbaik yang tersedia, berdasarkan penyedia lokasi yang saat ini tersedia seperti Wi-Fi dan GPS (Global Positioning System). Keakuratan lokasi ditentukan oleh penyedia, izin lokasi yang Anda minta, dan opsi yang Anda tetapkan dalam permintaan lokasi.

Tutorial ini menunjukkan kepada Anda cara meminta update rutin tentang lokasi perangkat menggunakan metode requestLocationUpdates() pada penyedia lokasi fusi.

Mendeklarasikan izin

Aplikasi yang menggunakan layanan lokasi harus meminta izin akses lokasi. Pada sebagian besar kasus, Anda dapat meminta izin akses lokasi sementara dan masih mendapatkan informasi lokasi yang cukup akurat dari penyedia lokasi yang tersedia.

Cuplikan berikut menunjukkan cara meminta izin akses lokasi sementara:

    <manifest ... >
      <uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION" />
    </manifest>
    
Screenshot dialog sisi pengguna
Gambar 1. Dialog ditampilkan ketika aplikasi meminta lokasi dengan opsi untuk hanya mengakses lokasi saat aplikasi sedang digunakan

Pada perangkat yang menjalankan Android 10 (API level 29) atau yang lebih tinggi, pengguna melihat dialog yang ditampilkan pada Gambar 1 untuk menunjukkan bahwa aplikasi Anda meminta izin akses lokasi. Jika pengguna memungkinkan akses aplikasi Anda ke lokasi perangkat dari dialog ini, aplikasi hanya dapat mengakses lokasi saat pengguna berinteraksi dengan aplikasi, bukan saat berjalan di latar belakang. Anda dapat mendeklarasikan layanan latar depan, yang memungkinkan aplikasi Anda mendapatkan detail lokasi untuk melanjutkan tindakan yang dimulai pengguna setelah pengguna mengirimkan aplikasi ke latar belakang.

Catatan: Meskipun dimungkinkan untuk meminta akses ke lokasi latar belakang jika aplikasi Anda berjalan pada Android 10 atau yang lebih baru, sebaiknya Anda tidak melakukannya.

Mendapatkan lokasi terakhir yang diketahui

Lokasi terakhir yang diketahui dari perangkat ini menyediakan basis praktis untuk memulai, memastikan bahwa aplikasi memiliki lokasi yang diketahui sebelum memulai update lokasi berkala. Tutorial mengenai Mendapatkan Lokasi Terakhir yang Diketahui menunjukkan kepada Anda cara mendapatkan lokasi terakhir yang diketahui dengan memanggil getLastLocation(). Cuplikan di bagian berikut mengasumsikan bahwa aplikasi Anda telah mengambil lokasi terakhir yang diketahui dan menyimpannya sebagai objek Location dalam mCurrentLocation variabel global.

Meminta update lokasi

Sebelum meminta update lokasi, aplikasi Anda harus terhubung ke layanan lokasi dan membuat permintaan lokasi. Tutorial mengenai Mengubah Setelan Lokasi menunjukkan kepada Anda cara melakukannya. Setelah ada permintaan lokasi, Anda dapat memulai update rutin dengan memanggil requestLocationUpdates().

Bergantung pada bentuk permintaan, penyedia lokasi fusi akan memanggil metode callback LocationCallback.onLocationResult() dan meneruskan daftar objek Location, atau mengeluarkan PendingIntent yang berisi lokasi dalam data yang diperluas. Keakuratan dan frekuensi update dipengaruhi oleh izin lokasi yang Anda minta dan opsi yang Anda tetapkan pada objek permintaan lokasi.

Tutorial ini menunjukkan cara mendapatkan update menggunakan pendekatan callback LocationCallback. Panggil requestLocationUpdates(), yang meneruskan instance dari objek LocationRequest, dan LocationCallback. Tentukan metode startLocationUpdates() seperti yang ditunjukkan dalam contoh kode berikut:

Kotlin

    override fun onResume() {
        super.onResume()
        if (requestingLocationUpdates) startLocationUpdates()
    }

    private fun startLocationUpdates() {
        fusedLocationClient.requestLocationUpdates(locationRequest,
                locationCallback,
                null /* Looper */)
    }
    

Java

    @Override
    protected void onResume() {
        super.onResume();
        if (requestingLocationUpdates) {
            startLocationUpdates();
        }
    }

    private void startLocationUpdates() {
        fusedLocationClient.requestLocationUpdates(locationRequest,
                locationCallback,
                null /* Looper */);
    }
    

Perhatikan bahwa cuplikan kode di atas mengacu pada flag boolean, requestingLocationUpdates, yang digunakan untuk melacak apakah pengguna mengaktifkan atau menonaktifkan update lokasi. Jika pengguna telah menonaktifkan update lokasi, Anda dapat memberi tahu mereka tentang persyaratan lokasi aplikasi. Untuk informasi selengkapnya tentang mempertahankan nilai flag boolean melalui instance aktivitas, lihat Menyimpan Status Aktivitas.

Menentukan callback update lokasi

Penyedia lokasi fusi memanggil metode callback LocationCallback.onLocationResult(). Argumen yang masuk memuat daftar objek Location yang berisi lintang dan bujur lokasi. Cuplikan berikut menunjukkan cara mengimplementasikan antarmuka LocationCallback dan mendefinisikan metode, kemudian mendapatkan stempel waktu update lokasi, serta menampilkan lintang, bujur, dan stempel waktu pada antarmuka pengguna aplikasi:

Kotlin

    private lateinit var locationCallback: LocationCallback

    // ...

    override fun onCreate(savedInstanceState: Bundle?) {
        // ...

        locationCallback = object : LocationCallback() {
            override fun onLocationResult(locationResult: LocationResult?) {
                locationResult ?: return
                for (location in locationResult.locations){
                    // Update UI with location data
                    // ...
                }
            }
        }
    }
    

Java

    private LocationCallback locationCallback;

    // ...

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        // ...

        locationCallback = new LocationCallback() {
            @Override
            public void onLocationResult(LocationResult locationResult) {
                if (locationResult == null) {
                    return;
                }
                for (Location location : locationResult.getLocations()) {
                    // Update UI with location data
                    // ...
                }
            };
        };
    }
    

Meminta akses ke lokasi latar belakang

Jika aplikasi Anda menargetkan Android 10 atau yang lebih tinggi, Anda harus mendeklarasikan izin ACCESS_BACKGROUND_LOCATION dalam file manifes aplikasi dan menerima izin pengguna untuk menerima update lokasi rutin saat aplikasi Anda berada di latar belakang.

Cuplikan kode tersebut menunjukkan cara meminta akses lokasi latar belakang dalam aplikasi Anda:

    <manifest ... >
      <uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION" />
      <uses-permission android:name="android.permission.ACCESS_BACKGROUND_LOCATION" />
    </manifest>
    
Screenshot dialog sisi pengguna
Gambar 2. Dialog ditampilkan saat aplikasi meminta lokasi dengan opsi untuk mengakses lokasi sepanjang waktu, termasuk saat berada di latar belakang.

Pada perangkat yang menjalankan Android 10 (API level 29) atau yang lebih tinggi, pengguna akan melihat dialog yang ditampilkan pada gambar 2 untuk menunjukkan bahwa aplikasi Anda meminta izin akses lokasi dan juga meminta akses ke lokasi sepanjang waktu, termasuk saat berada di latar belakang. Dialog ini menyertakan opsi bagi pengguna untuk memberikan aplikasi Anda akses ke lokasi hanya saat menggunakan aplikasi; jika pengguna memilih opsi ini, aplikasi Anda tidak memiliki akses ke lokasi saat berada di latar belakang. Jika alur kerja aplikasi Anda memerlukan akses sepanjang waktu ke informasi lokasi, Anda harus memberi tahu pengguna tentang persyaratan lokasi latar belakang aplikasi Anda.

Perhatian: Meskipun jika pengguna awalnya memberikan aplikasi Anda akses ke informasi lokasi saat berada di latar belakang, pengguna nantinya dapat mencabut izin ini dalam setelan sistem. Pengguna dapat memilih untuk memberikan aplikasi Anda akses ke informasi lokasi hanya saat mereka sedang menggunakan aplikasi Anda, atau mereka dapat memilih untuk tidak memberikan akses aplikasi Anda ke lokasi sama sekali.

Karena alasan ini, setiap kali aplikasi Anda memulai layanan, periksa apakah pengguna masih mengizinkan aplikasi Anda mengakses informasi lokasi di latar belakang atau tidak.

Pengingat akses lokasi latar belakang yang dilihat pengguna

Screenshot notifikasi sistem
Gambar 3. Notifikasi yang mengingatkan pengguna bahwa mereka telah memberikan akses aplikasi "sepanjang waktu" ke lokasi perangkat

Pengguna dapat memilih untuk mengizinkan akses sepanjang waktu ke lokasi perangkat. Saat aplikasi Anda mengakses lokasi perangkat di latar belakang untuk pertama kalinya setelah pengguna membuat pilihan ini, sistem akan menjadwalkan notifikasi untuk dikirimkan kepada pengguna. Notifikasi ini mengingatkan pengguna bahwa mereka mengizinkan aplikasi untuk mengakses lokasi perangkat sepanjang waktu. Contoh notifikasi muncul pada Gambar 3.

Memberi tahu pengguna tentang persyaratan lokasi latar belakang

Jika pengguna telah meminta agar aplikasi Anda mengakses lokasi hanya saat mereka menggunakan aplikasi, tampilkan dialog kustom untuk memberi tahu pengguna bahwa alur kerja dalam aplikasi Anda tidak dapat berfungsi dengan baik tanpa akses ke lokasi mereka sepanjang waktu.

Perhatian: Pengguna memiliki opsi untuk menolak secara serentak akses ke lokasi perangkat dan mencegah aplikasi Anda meminta akses ke lokasi perangkat pada masa mendatang. Aplikasi Anda harus mengikuti dan menangani keputusan "tolak dan jangan tanya lagi" ini.

Setelah pengguna menerima dialog ini, Anda dapat meminta lokasi latar belakang, dan pada saat itu dialog sistem yang ditunjukkan pada Gambar 4 akan muncul:

Screenshot dialog sisi pengguna
Gambar 4. Dialog yang meminta persetujuan pengguna untuk akses setiap saat ke lokasi

Contoh logika pemeriksaan izin ini muncul di cuplikan kode berikut:

Kotlin

    val permissionAccessCoarseLocationApproved = ActivityCompat
        .checkSelfPermission(this, permission.ACCESS_COARSE_LOCATION) ==
        PackageManager.PERMISSION_GRANTED

    if (permissionAccessCoarseLocationApproved) {
       val backgroundLocationPermissionApproved = ActivityCompat
           .checkSelfPermission(this, permission.ACCESS_BACKGROUND_LOCATION) ==
           PackageManager.PERMISSION_GRANTED

       if (backgroundLocationPermissionApproved) {
           // App can access location both in the foreground and in the background.
           // Start your service that doesn't have a foreground service type
           // defined.
       } else {
           // App can only access location in the foreground. Display a dialog
           // warning the user that your app must have all-the-time access to
           // location in order to function properly. Then, request background
           // location.
           ActivityCompat.requestPermissions(this,
               arrayOf(Manifest.permission.ACCESS_BACKGROUND_LOCATION),
               your-permission-request-code
           )
       }
    } else {
       // App doesn't have access to the device's location at all. Make full request
       // for permission.
       ActivityCompat.requestPermissions(this,
           arrayOf(Manifest.permission.ACCESS_COARSE_LOCATION,
                   Manifest.permission.ACCESS_BACKGROUND_LOCATION),
           your-permission-request-code
       )
    }
    

Java

    boolean permissionAccessCoarseLocationApproved =
        ActivityCompat.checkSelfPermission(this, permission.ACCESS_COARSE_LOCATION)
            == PackageManager.PERMISSION_GRANTED;

    if (permissionAccessCoarseLocationApproved) {
       boolean backgroundLocationPermissionApproved =
               ActivityCompat.checkSelfPermission(this,
                   permission.ACCESS_BACKGROUND_LOCATION)
                   == PackageManager.PERMISSION_GRANTED;

       if (backgroundLocationPermissionApproved) {
           // App can access location both in the foreground and in the background.
           // Start your service that doesn't have a foreground service type
           // defined.
       } else {
           // App can only access location in the foreground. Display a dialog
           // warning the user that your app must have all-the-time access to
           // location in order to function properly. Then, request background
           // location.
           ActivityCompat.requestPermissions(this, new String[] {
               Manifest.permission.ACCESS_BACKGROUND_LOCATION},
               your-permission-request-code);
       }
    } else {
       // App doesn't have access to the device's location at all. Make full request
       // for permission.
       ActivityCompat.requestPermissions(this, new String[] {
            Manifest.permission.ACCESS_COARSE_LOCATION,
            Manifest.permission.ACCESS_BACKGROUND_LOCATION
            },
            your-permission-request-code);
    }
    

Melanjutkan tindakan yang dimulai pengguna

Aplikasi Anda mungkin menawarkan alur kerja yang bergantung pada lokasi, seperti menggunakan navigasi belokan demi belokan saat mengemudi atau menelusuri jalur saat berjalan. Saat pengguna melakukan jenis tugas ini, aplikasi Anda biasanya perlu mengakses lokasi perangkat setelah ditempatkan di latar belakang, seperti saat pengguna menekan tombol Layar Utama di perangkat mereka atau menonaktifkan layar perangkat.

Untuk mempertahankan akses ke lokasi perangkat dalam kasus penggunaan yang spesifik ini, mulailah layanan latar depan yang telah Anda nyatakan memiliki jenis layanan latar depan ""location"" dalam manifes aplikasi Anda:

    <service
        android:name="MyNavigationService"
        android:foregroundServiceType="location" ... >
        ...
    </service>
    

Sebelum memulai layanan latar depan, pastikan aplikasi Anda masih memiliki akses ke lokasi perangkat:

Kotlin

    val permissionAccessCoarseLocationApproved = ActivityCompat
        .checkSelfPermission(this, permission.ACCESS_COARSE_LOCATION) ==
        PackageManager.PERMISSION_GRANTED

    if (permissionAccessCoarseLocationApproved) {
       // App has permission to access location in the foreground. Start your
       // foreground service that has a foreground service type of "location".
    } else {
       // Make a request for foreground-only location access.
       ActivityCompat.requestPermissions(this,
           arrayOf(Manifest.permission.ACCESS_COARSE_LOCATION),
           your-permission-request-code
       )
    }
    

Java

    boolean permissionAccessCoarseLocationApproved =
        ActivityCompat.checkSelfPermission(this,
            permission.ACCESS_COARSE_LOCATION) ==
            PackageManager.PERMISSION_GRANTED;

    if (permissionAccessCoarseLocationApproved) {
        // App has permission to access location in the foreground. Start your
        // foreground service that has a foreground service type of "location".
    } else {
       // Make a request for foreground-only location access.
       ActivityCompat.requestPermissions(this, new String[] {
            Manifest.permission.ACCESS_COARSE_LOCATION},
           your-permission-request-code);
    }
    

Menghentikan update lokasi

Pertimbangkan apakah Anda ingin menghentikan update lokasi saat aktivitas tidak lagi difokuskan, seperti saat pengguna beralih ke aplikasi lain atau ke aktivitas yang berbeda di aplikasi yang sama. Hal ini dapat berguna untuk mengurangi konsumsi daya, aplikasi yang disediakan tidak perlu mengumpulkan informasi bahkan jika aplikasi berjalan di latar belakang. Bagian ini menunjukkan cara Anda dapat menghentikan update dalam metode onPause() aktivitas.

Untuk menghentikan update lokasi, panggil removeLocationUpdates(), yang meneruskan LocationCallback, seperti yang ditunjukkan pada contoh kode berikut:

Kotlin

    override fun onPause() {
        super.onPause()
        stopLocationUpdates()
    }

    private fun stopLocationUpdates() {
        fusedLocationClient.removeLocationUpdates(locationCallback)
    }
    

Java

    @Override
    protected void onPause() {
        super.onPause();
        stopLocationUpdates();
    }

    private void stopLocationUpdates() {
        fusedLocationClient.removeLocationUpdates(locationCallback);
    }
    

Gunakan boolean, mRequestingLocationUpdates, untuk melacak apakah update lokasi saat ini diaktifkan atau tidak. Dalam metode onResume() aktivitas, periksa apakah update lokasi saat ini aktif, dan aktifkan jika tidak:

Kotlin

    override fun onResume() {
        super.onResume()
        if (requestingLocationUpdates) startLocationUpdates()
    }
    

Java

    @Override
    protected void onResume() {
        super.onResume();
        if (requestingLocationUpdates) {
            startLocationUpdates();
        }
    }
    

Menyimpan status aktivitas

Perubahan pada konfigurasi perangkat, seperti perubahan orientasi layar atau bahasa, dapat menyebabkan aktivitas saat ini diakhiri. Oleh karena itu, aplikasi Anda harus menyimpan informasi apa pun yang diperlukan untuk membuat ulang aktivitas. Salah satu cara untuk melakukannya adalah melalui status instance yang disimpan dalam objek Bundle.

Contoh kode berikut menampilkan cara menggunakan callback onSaveInstanceState() untuk menyimpan status instance:

Kotlin

    override fun onSaveInstanceState(outState: Bundle?) {
        outState?.putBoolean(REQUESTING_LOCATION_UPDATES_KEY, requestingLocationUpdates)
        super.onSaveInstanceState(outState)
    }
    

Java

    @Override
    protected void onSaveInstanceState(Bundle outState) {
        outState.putBoolean(REQUESTING_LOCATION_UPDATES_KEY,
                requestingLocationUpdates);
        // ...
        super.onSaveInstanceState(outState);
    }
    

Definisikan metode updateValuesFromBundle() untuk memulihkan nilai tersimpan dari instance sebelumnya dari aktivitas, jika nilai tersebut tersedia. Panggil metode dari metode onCreate() aktivitas, seperti yang ditunjukkan pada contoh kode berikut:

Kotlin

    override fun onCreate(savedInstanceState: Bundle?) {
        // ...
        updateValuesFromBundle(savedInstanceState)
    }

    private fun updateValuesFromBundle(savedInstanceState: Bundle?) {
        savedInstanceState ?: return

        // Update the value of requestingLocationUpdates from the Bundle.
        if (savedInstanceState.keySet().contains(REQUESTING_LOCATION_UPDATES_KEY)) {
            requestingLocationUpdates = savedInstanceState.getBoolean(
                    REQUESTING_LOCATION_UPDATES_KEY)
        }

        // ...

        // Update UI to match restored state
        updateUI()
    }
    

Java

    @Override
    public void onCreate(Bundle savedInstanceState) {
        // ...
        updateValuesFromBundle(savedInstanceState);
    }

    private void updateValuesFromBundle(Bundle savedInstanceState) {
        if (savedInstanceState == null) {
            return;
        }

        // Update the value of requestingLocationUpdates from the Bundle.
        if (savedInstanceState.keySet().contains(REQUESTING_LOCATION_UPDATES_KEY)) {
            requestingLocationUpdates = savedInstanceState.getBoolean(
                    REQUESTING_LOCATION_UPDATES_KEY);
        }

        // ...

        // Update UI to match restored state
        updateUI();
    }
    

Untuk informasi selengkapnya tentang status instance, lihat referensi class Aktivitas Android.

Catatan: Untuk penyimpanan yang lebih persisten, Anda dapat menyimpan preferensi pengguna dalam SharedPreferences aplikasi. Tetapkan preferensi bersama dalam metode onPause() aktivitas Anda,dan ambil preferensi dalam onResume(). Untuk informasi selengkapnya tentang menyimpan preferensi, baca Menyimpan Rangkaian Nilai Kunci.

Tutorial berikutnya, Menampilkan alamat lokasi, menunjukkan cara menampilkan alamat jalan untuk lokasi yang diberikan.

Referensi lainnya

Untuk mempelajari lebih lanjut, manfaatkan referensi berikut:

Contoh