Ringkasan LiveData   Bagian dari Android Jetpack.

LiveData adalah class penyimpanan data observable. Tidak seperti observable pada umumnya, LiveData berbasis siklus proses, yang berarti observable ini mengikuti siklus proses komponen aplikasi lainnya, seperti aktivitas, fragmen, atau layanan. Basis ini memastikan LiveData hanya mengupdate pengamat komponen aplikasi yang dalam status siklus proses aktif.

LiveData menganggap pengamat, yang diwakili oleh class Observer, berstatus aktif jika siklus prosesnya berada dalam status STARTED atau RESUMED. LiveData hanya memberitahukan update kepada pengamat aktif. Pengamat nonaktif yang terdaftar untuk mengawasi objek LiveData tidak diberi tahu tentang perubahan.

Anda dapat mendaftarkan pengamat yang dipasangkan dengan objek yang mengimplementasikan antarmuka LifecycleOwner. Hubungan ini memungkinkan pengamat dihapus saat status objek Lifecycle terkait berubah menjadi DESTROYED. Ini sangat berguna untuk aktivitas dan fragmen karena keduanya dapat mengamati objek LiveData dengan aman tanpa perlu mengkhawatirkan kebocoran—aktivitas dan fragmen akan segera berhenti mengamati saat siklus proses keduanya diakhiri.

Untuk informasi selengkapnya tentang cara penggunaan LiveData, lihat Bekerja menggunakan objek LiveData.

Keuntungan penggunaan LiveData

Penggunaan LiveData memberikan keuntungan berikut:

Memastikan UI cocok dengan status data
LiveData mengikuti pola pengamat. LiveData memberi tahu objek Observer saat status siklus proses berubah. Anda dapat menggabungkan kode untuk mengupdate UI di objek Observer ini. Daripada mengupdate UI setiap kali data aplikasi berubah, pengamat Anda dapat mengupdate UI setiap kali terjadi perubahan.
Tidak ada kebocoran memori
Pengamat terikat pada objek Lifecycle dan mengosongkan sisa proses saat siklus proses pengamat diakhiri.
Penghentian proses tidak menyebabkan error
Jika siklus proses pengamat tidak aktif, seperti dalam kasus aktivitas di data sebelumnya, maka siklus proses pengamat tidak menerima peristiwa LiveData apa pun.
Tidak ada lagi penanganan siklus proses manual
Komponen UI hanya mengamati data yang relevan dan tidak menghentikan atau melanjutkan pengamatan. LiveData otomatis mengelola semua ini karena LiveData mengetahui terjadinya perubahan status siklus proses terkait saat melakukan pengamatan.
Data selalu diperbarui
Jika siklus proses menjadi nonaktif, siklus proses menerima data terbaru setelah aktif kembali. Misalnya, aktivitas yang berada di latar belakang menerima data terbaru setelah kembali digunakan di latar depan.
Perubahan konfigurasi yang tepat
Jika suatu aktivitas atau fragmen dibuat kembali karena perubahan konfigurasi, seperti rotasi perangkat, aktivitas atau fragmen tersebut segera menerima data terbaru yang tersedia.
Berbagi resource
Anda dapat memperluas objek LiveData menggunakan pola singleton untuk menggabungkan layanan sistem sehingga dapat dibagikan di aplikasi Anda. Objek LiveData terhubung ke layanan sistem satu kali, dan setiap pengamat yang membutuhkan resource tersebut dapat langsung mengamati objek LiveData. Untuk informasi selengkapnya, lihat Memperluas LiveData.

Bekerja menggunakan objek LiveData

Ikuti langkah-langkah berikut untuk bekerja menggunakan objek LiveData:

  1. Buat instance LiveData untuk menyimpan jenis data tertentu. Ini biasanya dilakukan dalam class ViewModel.
  2. Buat objek Observer yang menentukan metode onChanged(), yang mengontrol hal yang terjadi saat objek milik LiveData menyimpan perubahan data. Anda biasanya membuat objek Observer dalam pengontrol UI, seperti aktivitas atau fragmen.
  3. Lampirkan objek Observer ke objek LiveData menggunakan metode observe(). Metode observe() mengambil objek LifecycleOwner. Hal ini mendaftarkan objek Observer ke objek LiveData sehingga objek tersebut akan mendapatkan pemberitahuan perubahan. Anda biasanya melampirkan objek Observer dalam pengontrol UI, seperti aktivitas atau fragmen.

Saat Anda mengupdate nilai yang tersimpan dalam objek LiveData, proses update memicu semua pengamat terdaftar selama LifecycleOwner terlampir masih dalam keadaan aktif.

LiveData memungkinkan pengamat pengontrol UI untuk mendapatkan informasi update. Saat data yang disimpan objek LiveData berubah, UI merespons dengan otomatis melakukan update.

Membuat objek LiveData

LiveData adalah wrapper yang dapat digunakan dengan data apa pun, termasuk objek yang mengimplementasikan Collections, seperti List. Objek LiveData biasanya disimpan dalam objek ViewModel dan diakses melalui metode pengambil, seperti yang ditunjukkan dalam contoh berikut:

Kotlin

    class NameViewModel : ViewModel() {

        // Create a LiveData with a String
        val currentName: MutableLiveData<String> by lazy {
            MutableLiveData<String>()
        }

        // Rest of the ViewModel...
    }
    

Java

    public class NameViewModel extends ViewModel {

    // Create a LiveData with a String
    private MutableLiveData<String> currentName;

        public MutableLiveData<String> getCurrentName() {
            if (currentName == null) {
                currentName = new MutableLiveData<String>();
            }
            return currentName;
        }

    // Rest of the ViewModel...
    }
    

Awalnya, data dalam objek LiveData belum ditetapkan.

Anda dapat membaca selengkapnya tentang manfaat dan penggunaan class ViewModel di panduan ViewModel.

Mengamati objek LiveData

Dalam sebagian besar kasus, metode onCreate() komponen aplikasi adalah tempat yang tepat untuk mulai mengamati objek LiveData karena alasan berikut:

  • Untuk memastikan sistem tidak melakukan panggilan yang berlebihan dari metode onResume() aktivitas atau fragmen.
  • Untuk memastikan aktivitas atau fragmen memiliki data yang dapat ditampilkan segera setelah aktif kembali. Segera setelah berada dalam status STARTED, komponen aplikasi menerima nilai terbaru dari objek LiveData yang diamatinya. Proses ini hanya terjadi jika objek LiveData yang akan diamati telah ditetapkan.

Umumnya, LiveData meneruskan update hanya saat data berubah, dan hanya untuk pengamat yang aktif. Pengecualian perilaku ini adalah saat pengamat juga menerima update saat mereka berubah dari status nonaktif menjadi aktif. Selanjutnya, jika status pengamat berubah dari nonaktif menjadi aktif untuk kedua kalinya, pengamat hanya menerima update jika nilai telah berubah sejak terakhir kali status pengamat menjadi aktif.

Kode contoh berikut menunjukkan cara memulai pengamatan objek LiveData:

Kotlin

    class NameActivity : AppCompatActivity() {

        // Use the 'by viewModels()' Kotlin property delegate
        // from the activity-ktx artifact
        private val model: NameViewModel by viewModels()

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

            // Other code to setup the activity...

            // Create the observer which updates the UI.
            val nameObserver = Observer<String> { newName ->
                // Update the UI, in this case, a TextView.
                nameTextView.text = newName
            }

            // Observe the LiveData, passing in this activity as the LifecycleOwner and the observer.
            model.currentName.observe(this, nameObserver)
        }
    }
    

Java

    public class NameActivity extends AppCompatActivity {

        private NameViewModel model;

        @Override
        protected void onCreate(Bundle savedInstanceState) {
            super.onCreate(savedInstanceState);

            // Other code to setup the activity...

            // Get the ViewModel.
            model = new ViewModelProvider(this).get(NameViewModel.class);

            // Create the observer which updates the UI.
            final Observer<String> nameObserver = new Observer<String>() {
                @Override
                public void onChanged(@Nullable final String newName) {
                    // Update the UI, in this case, a TextView.
                    nameTextView.setText(newName);
                }
            };

            // Observe the LiveData, passing in this activity as the LifecycleOwner and the observer.
            model.getCurrentName().observe(this, nameObserver);
        }
    }
    

Setelah observe() dipanggil dengan nameObserver diteruskan sebagai parameter, onChanged() segera dipanggil untuk memberikan nilai terbaru yang tersimpan di mCurrentName. Jika objek LiveData belum menetapkan nilai di mCurrentName, onChanged() tidak akan dipanggil.

Mengupdate objek LiveData

LiveData tidak memiliki metode yang tersedia untuk publik dalam memperbarui data tersimpan. Class MutableLiveData memperlihatkan metode setValue(T) dan postValue(T) secara publik, dan Anda harus menggunakan metode ini jika ingin mengedit nilai yang tersimpan di objek LiveData. Biasanya MutableLiveData digunakan dalam ViewModel dan ViewModel hanya memperlihatkan objek LiveData tetap kepada pengamat.

Setelah menyiapkan hubungan pengamat, selanjutnya Anda dapat memperbarui nilai objek LiveData seperti yang ditunjukkan oleh contoh berikut, yang memicu semua pengamat saat pengguna mengetuk suatu tombol:

Kotlin

    button.setOnClickListener {
        val anotherName = "John Doe"
        model.currentName.setValue(anotherName)
    }
    

Java

    button.setOnClickListener(new OnClickListener() {
        @Override
        public void onClick(View v) {
            String anotherName = "John Doe";
            model.getCurrentName().setValue(anotherName);
        }
    });
    

Memanggil setValue(T) seperti dalam contoh ini mengakibatkan pengamat memanggil metodeonChanged() dengan nilai John Doe. Contoh ini menunjukkan penekanan tombol, tetapi setValue() atau postValue() dapat saja dipanggil untuk mengupdate mName karena berbagai alasan, termasuk sebagai respons terhadap permintaan jaringan atau penyelesaian pemuatan database. Dalam semua kasus ini, panggilan terhadap setValue() atau postValue() memicu pengamat dan mengupdate UI.

Menggunakan LiveData dengan Room

Library tetap Room mendukung kueri observable, yang menampilkan objek LiveData sebagai hasil. Kueri observable ditulis sebagai bagian dari DAO (Objek Akses Database).

Room menghasilkan semua kode yang dibutuhkan untuk mengupdate objek LiveData saat database diupdate. Kode yang dihasilkan oleh Room menjalankan kueri secara asinkron di thread latar belakang saat diperlukan. Pola ini berguna untuk menjaga data agar yang ditampilkan di UI tetap tersinkronisasi dengan data yang tersimpan di database. Anda dapat membaca selengkapnya tentang Room dan DAO di panduan library persisten Room.

Menggunakan coroutine dengan LiveData

LiveData mencakup dukungan untuk coroutine Kotlin. Untuk informasi selengkapnya, lihat Menggunakan coroutine Kotlin dengan Komponen Arsitektur Android.

Memperluas LiveData

LiveData menganggap pengamat berada dalam keadaan aktif jika siklus proses pengamat berada dalam status STARTED atau RESUMED. Kode contoh berikut mengilustrasikan cara memperluas class LiveData:

Kotlin

    class StockLiveData(symbol: String) : LiveData<BigDecimal>() {
        private val stockManager = StockManager(symbol)

        private val listener = { price: BigDecimal ->
            value = price
        }

        override fun onActive() {
            stockManager.requestPriceUpdates(listener)
        }

        override fun onInactive() {
            stockManager.removeUpdates(listener)
        }
    }
    

Java

    public class StockLiveData extends LiveData<BigDecimal> {
        private StockManager stockManager;

        private SimplePriceListener listener = new SimplePriceListener() {
            @Override
            public void onPriceChanged(BigDecimal price) {
                setValue(price);
            }
        };

        public StockLiveData(String symbol) {
            stockManager = new StockManager(symbol);
        }

        @Override
        protected void onActive() {
            stockManager.requestPriceUpdates(listener);
        }

        @Override
        protected void onInactive() {
            stockManager.removeUpdates(listener);
        }
    }
    

Pengimplementasian pemantau harga dalam contoh ini juga menyertakan beberapa metode penting berikut:

  • Metode onActive() dipanggil saat objek LiveData memiliki pengamat aktif. Artinya, Anda harus mulai mengamati pembaruan harga saham dari metode ini.
  • Metode onInactive() dipanggil saat objek LiveData tidak memiliki pengamat aktif. Karena tidak ada pengamat yang memantau, tidak ada alasan untuk tetap terhubung dengan layanan StockManager.
  • Metode setValue(T) mengupdate nilai instance LiveData dan memberitahukan setiap pengamat aktif tentang perubahan tersebut.

Anda dapat menggunakan class StockLiveData dengan cara berikut:

Kotlin

    public class MyFragment : Fragment() {
        override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
            super.onViewCreated(view, savedInstanceState)
            val myPriceListener: LiveData<BigDecimal> = ...
            myPriceListener.observe(viewLifecycleOwner, Observer<BigDecimal> { price: BigDecimal? ->
                // Update the UI.
            })
        }
    }
    

Java

    public class MyFragment extends Fragment {
        @Override
        public void onViewCreated(@NonNull View view, @Nullable Bundle savedInstanceState) {
            super.onViewCreated(view, savedInstanceState);
            LiveData<BigDecimal> myPriceListener = ...;
            myPriceListener.observe(getViewLifeycleOwner(), price -> {
                // Update the UI.
            });
        }
    }
    

Metode observe() meneruskan LifecycleOwner yang terkait dengan tampilan fragment sebagai argumen pertama. Penerusan seperti itu menunjukkan bahwa pengamat ini terikat ke objek Lifecycle yang terkait dengan pemilik, yang berarti:

  • Jika objek Lifecycle tidak dalam status aktif, pengamat tidak akan dipanggil meskipun nilai berubah.
  • Setelah objek Lifecycle diakhiri, pengamat secara otomatis dihapus.

Fakta bahwa objek LiveData berbasis siklus proses berarti Anda dapat membagikan objek-objek ini di antara berbagai aktivitas, fragmen, dan layanan. Agar contoh tetap sederhana, Anda dapat mengimplementasikan class LiveData sebagai singleton dengan cara sebagai berikut:

Kotlin

    class StockLiveData(symbol: String) : LiveData<BigDecimal>() {
        private val stockManager: StockManager = StockManager(symbol)

        private val listener = { price: BigDecimal ->
            value = price
        }

        override fun onActive() {
            stockManager.requestPriceUpdates(listener)
        }

        override fun onInactive() {
            stockManager.removeUpdates(listener)
        }

        companion object {
            private lateinit var sInstance: StockLiveData

            @MainThread
            fun get(symbol: String): StockLiveData {
                sInstance = if (::sInstance.isInitialized) sInstance else StockLiveData(symbol)
                return sInstance
            }
        }
    }
    

Java

    public class StockLiveData extends LiveData<BigDecimal> {
        private static StockLiveData sInstance;
        private StockManager stockManager;

        private SimplePriceListener listener = new SimplePriceListener() {
            @Override
            public void onPriceChanged(BigDecimal price) {
                setValue(price);
            }
        };

        @MainThread
        public static StockLiveData get(String symbol) {
            if (sInstance == null) {
                sInstance = new StockLiveData(symbol);
            }
            return sInstance;
        }

        private StockLiveData(String symbol) {
            stockManager = new StockManager(symbol);
        }

        @Override
        protected void onActive() {
            stockManager.requestPriceUpdates(listener);
        }

        @Override
        protected void onInactive() {
            stockManager.removeUpdates(listener);
        }
    }
    

Dan Anda dapat menggunakannya di fragmen dengan cara berikut:

Kotlin

    class MyFragment : Fragment() {

        override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
            super.onViewCreated(view, savedInstanceState)
            StockLiveData.get(symbol).observe(viewLifecycleOwner, Observer<BigDecimal> { price: BigDecimal? ->
                // Update the UI.
            })

        }
    

Java

    public class MyFragment extends Fragment {
        @Override
        public void onViewCreated(@NonNull View view, @Nullable Bundle savedInstanceState) {
            super.onViewCreated(view, savedInstanceState);
            StockLiveData.get(symbol).observe(getViewLifecycleOwner(), price -> {
                // Update the UI.
            });
        }
    }
    

Beberapa fragmen dan aktivitas dapat mengamati instance MyPriceListener. LiveData hanya terhubung ke layanan sistem jika satu atau lebih fragmen dan aktivitas terlihat dan aktif.

Mentransformasi LiveData

Anda mungkin ingin mengubah nilai yang tersimpan dalam objek LiveData sebelum mengirimkannya ke pengamat, atau Anda mungkin perlu mengirimkan instance LiveData yang berbeda berdasarkan nilai instance yang lain. Paket Lifecycle menyediakan class Transformations yang mencakup metode penunjang yang mendukung skenario ini.

Transformations.map()
Menerapkan fungsi pada nilai yang tersimpan pada objek LiveData, dan menyebarkan hasilnya ke downstream.

Kotlin

    val userLiveData: LiveData<User> = UserLiveData()
    val userName: LiveData<String> = Transformations.map(userLiveData) {
        user -> "${user.name} ${user.lastName}"
    }
    

Java

    LiveData<User> userLiveData = ...;
    LiveData<String> userName = Transformations.map(userLiveData, user -> {
        user.name + " " + user.lastName
    });
    
Transformations.switchMap()
Sama seperti map(), menerapkan fungsi pada nilai yang tersimpan dalam objek LiveData dan mengurai serta mengirimkan hasilnya ke downstream. Fungsi yang diteruskan ke switchMap() harus mengembalikan objek LiveData, seperti yang ditunjukkan oleh contoh berikut:

Kotlin

    private fun getUser(id: String): LiveData<User> {
      ...
    }
    val userId: LiveData<String> = ...
    val user = Transformations.switchMap(userId) { id -> getUser(id) }
    

Java

    private LiveData<User> getUser(String id) {
      ...;
    }

    LiveData<String> userId = ...;
    LiveData<User> user = Transformations.switchMap(userId, id -> getUser(id) );
    

Anda dapat menggunakan metode transformasi untuk membawa informasi di seluruh siklus proses pengamat. Transformasi tidak dihitung kecuali suatu pengamat sedang mengamati objek LiveData yang ditampilkan. Karena transformasi dihitung hanya jika dibutuhkan, perilaku terkait siklus proses secara implisit diwariskan tanpa memerlukan panggilan atau dependensi eksplisit tambahan.

Jika Anda merasa memerlukan objek Lifecycle di dalam objek ViewModel, transformasi mungkin merupakan solusi yang lebih baik. Misalnya, anggap bahwa Anda memiliki komponen UI yang menerima alamat dan mengembalikan kode pos untuk alamat tersebut. Anda dapat mengimplementasikan ViewModel naif untuk komponen ini seperti yang ditunjukkan oleh kode contoh berikut:

Kotlin

    class MyViewModel(private val repository: PostalCodeRepository) : ViewModel() {

        private fun getPostalCode(address: String): LiveData<String> {
            // DON'T DO THIS
            return repository.getPostCode(address)
        }
    }
    

Java

    class MyViewModel extends ViewModel {
        private final PostalCodeRepository repository;
        public MyViewModel(PostalCodeRepository repository) {
           this.repository = repository;
        }

        private LiveData<String> getPostalCode(String address) {
           // DON'T DO THIS
           return repository.getPostCode(address);
        }
    }
    

Komponen UI ini kemudian perlu membatalkan pendaftaran dari objek LiveData sebelumnya dan mendaftar ke instance baru setiap kali komponen UI memanggil getPostalCode(). Selain itu, jika komponen UI dibuat kembali, komponen UI memicu panggilan lain ke metode repository.getPostCode() dan bukan menggunakan hasil panggilan sebelumnya.

Sebagai gantinya, Anda dapat mengimplementasikan pencarian kode pos sebagai transformasi masukan alamat, seperti yang ditunjukkan contoh berikut:

Kotlin

    class MyViewModel(private val repository: PostalCodeRepository) : ViewModel() {
        private val addressInput = MutableLiveData<String>()
        val postalCode: LiveData<String> = Transformations.switchMap(addressInput) {
                address -> repository.getPostCode(address) }

        private fun setInput(address: String) {
            addressInput.value = address
        }
    }
    

Java

    class MyViewModel extends ViewModel {
        private final PostalCodeRepository repository;
        private final MutableLiveData<String> addressInput = new MutableLiveData();
        public final LiveData<String> postalCode =
                Transformations.switchMap(addressInput, (address) -> {
                    return repository.getPostCode(address);
                 });

      public MyViewModel(PostalCodeRepository repository) {
          this.repository = repository
      }

      private void setInput(String address) {
          addressInput.setValue(address);
      }
    }
    

Dalam hal ini, kolom postalCode ditetapkan sebagai transformasi addressInput. Selama aplikasi Anda memiliki pengamat aktif yang terkait dengan kolom postalCode, nilai kolom tersebut dihitung ulang dan diambil setiap kali addressInput berubah.

Mekanisme ini memungkinkan tingkat aplikasi yang lebih rendah untuk membuat objek LiveData yang biasanya dihitung hanya jika dibutuhkan menjadi berdasarkan permintaan. Objek ViewModel dapat dengan mudah memperoleh referensi ke LiveData objek dan kemudian menentukan aturan transformasi di atas objek-objek tersebut.

Membuat transformasi baru

Ada berbagai transformasi khusus yang mungkin berguna pada aplikasi Anda, tetapi tidak disediakan secara default. Untuk mengimplementasikan transformasi Anda sendiri, Anda dapat menggunakan class MediatorLiveData yang memantau objek LiveData lain dan memproses peristiwa yang ditampilkan objek tersebut. MediatorLiveData dengan tepat menyebarkan statusnya ke objek LiveData sumber. Untuk mempelajari pola ini lebih lanjut, lihat dokumentasi referensi class Transformations.

Menggabungkan beberapa sumber LiveData

MediatorLiveData adalah subclass LiveData yang memungkinkan Anda menggabungkan beberapa sumber LiveData. Pengamat objek MediatorLiveData kemudian dipicu setiap kali objek sumber LiveData asli berubah.

Misalnya, jika Anda memiliki objek LiveData di UI yang dapat diupdate dari database lokal atau jaringan, Anda dapat menambahkan sumber berikut ke objek MediatorLiveData:

  • Objek LiveData yang terkait dengan data yang tersimpan dalam database.
  • Objek LiveData yang terkait dengan data yang diakses dari jaringan.

Aktivitas Anda hanya perlu mengamati objek MediatorLiveData untuk menerima update dari kedua sumber. Untuk contoh mendetail, lihat Addendum: memperlihatkan status jaringan dalam Panduan Arsitektur Aplikasi.

Resource lainnya

Untuk mempelajari lebih lanjut tentang class LiveData, lihat referensi berikut.

Contoh

Codelab

Blog

Video