Ringkasan LiveData   Bagian dari Android Jetpack.

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

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

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

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 hidup berubah. Anda dapat menggabungkan kode untuk mengupdate UI pada objek-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 hidup mereka dimusnahkan.
Penghentian proses tidak menyebabkan crash
Jika siklus hidup pengamat tidak aktif, seperti dalam kasus aktivitas di back stack, maka siklus hidup pengamat tidak menerima peristiwa LiveData apa pun.
Tidak ada lagi penanganan siklus hidup manual
Komponen UI hanya mengamati data yang relevan dan tidak menghentikan atau melanjutkan pengamatan. LiveData secara otomatis mengelola semua ini karena LiveData mengetahui terjadinya perubahan status siklus hidup terkait saat melakukan pengamatan.
Data selalu diperbarui
Jika siklus hidup menjadi nonaktif, siklus hidup 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 perangakt, aktivitas atau fragmen tersebut segera menerima data terbaru yang tersedia.
Berbagi resource
Anda dapat memperluas objek LiveData menggunakan pola singleton untuk mengemas layanan sistem sehingga dapat dibagikan di aplikasi Anda. Objek LiveData terhubung ke layanan sistem satu kali, kemudian pengamat apa pun yang memerlukan resource dapat langsung mengamati objek LiveData . Untuk informasi selengkapnya, lihat Memperluas LiveData.

Bekerja menggunakan objek LiveData

Ikuti langkah-langkah ini untuk bekerja menggunakan objek LiveData:

  1. Buatlah instance LiveData untuk menyimpan jenis data tertentu. Pembuatan instance ini biasanya dibuat di dalam class ViewModel.
  2. Buat objek Observer yang mendefinisikan metode onChanged() , yang mengontrol hal yang terjadi saat objek milik LiveData menyimpan perubahan data. Anda biasanya membuat objek Observer di pengontrol UI, seperti aktivitas dan 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 di objek LiveData, proses update memicu semua pengamat yang terdaftar selama LifecycleOwner terlampir masih dalam keadaan aktif.

LiveData memungkinkan pengamat pengontrol UI untuk mendapatkan informasi update. Saat data yang dipegang oleh objek LiveData berubah, UI juga merespons dengan secara otomatis mengupdate.

Membuat objek LiveData

LiveData adalah wrapper yang dapat digunakan dengan data apa saja, termasuk objek yang mengimplementasikan Collections, seperti List. Objek LiveData biasanya disimpan dalam objek ViewModel dan diakses menggunakan metode getter, 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 manfaat dan penggunaan class ViewModel di panduan ViewModel.

Mengamati objek LiveData

Dalam kebanyakan kasus, metode onCreate() komponen aplikasi merupakan tempat yang tepat untuk mulai mengamati objek LiveData karena alasan sebagai 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() {

        private lateinit var model: NameViewModel

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

            // Other code to setup the activity...

            // Get the ViewModel.
            model = ViewModelProviders.of(this).get(NameViewModel::class.java)

            // 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 = ViewModelProviders.of(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 kemudian 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 metode onChanged() dengan nilai John Doe. Contoh ini menunjukkan penekanan tombol, tetapi setValue() atau postValue() dapat saja dipanggil untuk memperbarui 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).

Roommenghasilkan 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 berstatus aktif jika siklus hidup 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 satu pun pengamat aktif. Karena tidak ada pengamat yang memantau, tidak ada alasan untuk tetap terhubung dengan layanan StockManager.
  • Metode setValue(T) memperbarui nilai LiveData dan memberitahukan perubahan tersebut kepada pengamat aktif.

Anda dapat menggunakan class StockLiveData dengan cara berikut:

Kotlin

    override fun onActivityCreated(savedInstanceState: Bundle?) {
        super.onActivityCreated(savedInstanceState)
        val myPriceListener: LiveData<BigDecimal> = ...
        myPriceListener.observe(this, Observer<BigDecimal> { price: BigDecimal? ->
            // Update the UI.
        })
    }
    

Java

    public class MyFragment extends Fragment {
        @Override
        public void onActivityCreated(Bundle savedInstanceState) {
            super.onActivityCreated(savedInstanceState);
            LiveData<BigDecimal> myPriceListener = ...;
            myPriceListener.observe(this, price -> {
                // Update the UI.
            });
        }
    }
    

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

  • Jika objek Lifecycle tidak berstatus aktif, maka pengamat tidak akan dipanggil bahkan jika nilai berubah.
  • Setelah objek Lifecycle dimusnahkan, pengamat secara otomatis dihapus.

Fakta bahwa objek LiveData adalah berbasis siklus hidup 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 onActivityCreated(savedInstanceState: Bundle?) {
            StockLiveData.get(symbol).observe(this, Observer<BigDecimal> { price: BigDecimal? ->
                // Update the UI.
            })

        }
    

Java

    public class MyFragment extends Fragment {
        @Override
        public void onActivityCreated(Bundle savedInstanceState) {
            StockLiveData.get(symbol).observe(this, price -> {
                // Update the UI.
            });
        }
    }
    

Berbagai 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 menyertakan 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(), fungsinya menerapkan nilai yang tersimpan pada objek LiveData dan membongkar serta mengirimkan hasilnya ke downstream. Fungsi yang diteruskan ke switchMap() harus menampilkan 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 hidup pengamat. Transformasi tidak dihitung kecuali suatu pengamat sedang mengamati objek LiveData yang ditampilkan. Karena transformasi dihitung hanya jika dibutuhkan, perilaku terkait siklus hidup secara implisit diwariskan tanpa memerlukan panggilan atau dependensi eksplisit tambahan.

Jika Anda berpikir bahwa Anda membutuhkan 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 ditentukan sebagai transformasi dari addressInput. Selama aplikasi 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 memperoleh referensi ke objek LiveData dengan mudah, 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. 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 terpicu setiap kali salah satu objek sumber LiveData berubah.

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

  • Objek LiveData yang terkait dengan data yang tersimpan di database.
  • Objek LiveData yang terkait dengan data yang diakss dari jaringan.

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

Referensi lainnya

Untuk mempelajari lebih lanjut class LiveData, lihat referensi berikut.

Contoh

Codelab

Blog

Video