Tổng quan về LiveData Một phần của Android Jetpack.
LiveData là một lớp lưu giữ dữ liệu có thể quan sát. Không như một lớp có thể quan sát thông thường, LiveData có tính năng nhận biết được vòng đời, nghĩa là tính năng này tuân theo vòng đời của các thành phần khác trong ứng dụng, chẳng hạn như các hoạt động, mảnh hoặc dịch vụ. Khả năng nhận biết này đảm bảo rằng LiveData chỉ cập nhật những trình quan sát thành phần của ứng dụng ở trạng thái vòng đời đang hoạt động.
LiveData sẽ coi trạng thái của một trình quan sát được đại diện bởi lớp Observer là đang hoạt động nếu vòng đời của lớp đó ở vào trạng tháiSTARTED hoặc RESUMED. LiveData chỉ thông báo các thông tin cập nhật cho trình quan sát đang hoạt động. Các trình quan sát không hoạt động đã đăng ký quan sát đối tượng LiveData sẽ không được thông báo về các thay đổi.
Bạn có thể đăng ký cho một trình quan sát ghép nối với đối tượng sẽ triển khai giao diện LifecycleOwner. Mối quan hệ này cho phép xoá trình quan sát khi trạng thái của đối tượng Lifecycle tương ứng thay đổi thành DESTROYED.
Điều này đặc biệt hữu ích cho các hoạt động và mảnh vì chúng có thể quan sát các đối tượng LiveData một cách an toàn và không phải lo lắng về nguy cơ rò rỉ—các hoạt động và mảnh sẽ bị hủy đăng ký ngay khi vòng đời của chúng bị hủy bỏ.
Để biết thêm thông tin về cách sử dụng LiveData, hãy xem phần Làm việc với các đối tượng LiveData.
Ưu điểm của việc sử dụng LiveData
Việc sử dụng LiveData mang lại những lợi ích sau:
- Đảm bảo giao diện người dùng khớp với trạng thái dữ liệu
- LiveData tuân theo mẫu của trình quan sát. LiveData thông báo cho các đối tượng
Observerkhi dữ liệu cơ sở thay đổi. Bạn có thể hợp nhất mã để cập nhật giao diện người dùng trong các đối tượngObservernày. Nhờ đó, bạn không cần phải cập nhật giao diện người dùng mỗi khi dữ liệu ứng dụng thay đổi, vì trình quan sát sẽ làm việc đó thay cho bạn. - Không rò rỉ bộ nhớ
- Trình quan sát được liên kết với các đối tượng
Lifecyclevà tự xoá sau khi vòng đời liên kết với các đối tượng bị huỷ bỏ. - Không có sự cố do các hoạt động đã dừng
- Nếu vòng đời của trình quan sát không hoạt động, chẳng hạn như trong một hoạt động ở ngăn xếp lui, thì trình quan sát sẽ không nhận được bất kỳ sự kiện LiveData nào.
- Không còn phải xử lý vòng đời theo cách thủ công
- Các thành phần giao diện người dùng chỉ quan sát các dữ liệu liên quan và không ngừng hoặc tiếp tục việc quan sát. LiveData tự động quản lý tất cả những việc này nhờ khả năng nhận biết những thay đổi trạng thái liên quan đến vòng đời trong khi quan sát.
- Luôn luôn cập nhật dữ liệu
- Vòng đời không hoạt động sẽ nhận được dữ liệu mới nhất sau khi được kích hoạt trở lại. Ví dụ, một hoạt động chạy dưới nền sẽ nhận được dữ liệu mới nhất ngay sau khi hoạt động đó chuyển về chay trên nền trước.
- Thay đổi cấu hình phù hợp
- Nếu một hoạt động hoặc mảnh được tạo lại do có sự thay đổi về cấu hình, chẳng hạn như xoay thiết bị, thì hoạt động hoặc mảnh đó sẽ ngay lập tức nhận được dữ liệu mới nhất hiện có.
- Chia sẻ tài nguyên
- Bạn có thể mở rộng một đối tượng
LiveDatabằng mẫu singleton để gói và chia sẻ các dịch vụ hệ thống trong ứng dụng. Đối tượngLiveDatasẽ kết nối với dịch vụ hệ thống một lần, sau đó bất kỳ trình quan sát nào cần tài nguyên có thể chỉ cần xem đối tượngLiveData. Để biết thêm thông tin, hãy xem phần Mở rộng LiveData.
Làm việc với các đối tượng LiveData
Làm theo các bước sau để làm việc với các đối tượng LiveData:
- Tạo một thực thể của
LiveDatađể lưu giữ một loại dữ liệu nhất định. Bước này thường được thực hiện trong lớpViewModel. - Tạo một đối tượng
Observerđể xác định phương thứconChanged(). Phương thức này sẽ kiểm soát hành động diễn ra khi đối tượngLiveDatathay đổi dữ liệu đã lưu giữ. Bạn thường tạo một đối tượngObservertrong bộ điều khiển trên giao diện người dùng, chẳng hạn như một hoạt động hoặc mảnh. Gắn đối tượng
Observervào đối tượngLiveDatabằng phương thứcobserve(). Phương thứcobserve()sẽ nhận đối tượngLifecycleOwner. Thao tác này sẽ đăng ký đối tượngObservervới đối tượngLiveDatađể được thông báo về các thay đổi. Bạn thường đính kèm đối tượngObservertrong bộ điều khiển giao diện người dùng, chẳng hạn như hoạt động hoặc mảnh.
Khi cập nhật giá trị được lưu trữ trong đối tượng LiveData, thao tác này sẽ kích hoạt tất cả các trình quan sát đã đăng ký, miễn là LifecycleOwner đính kèm vẫn ở trạng thái đang hoạt động.
LiveData cho phép trình quan sát giao diện người dùng đăng ký nhận nội dung cập nhật. Khi dữ liệu do đối tượng LiveData lưu giữ thay đổi, giao diện người dùng sẽ tự động cập nhật để phản hồi.
Tạo đối tượng LiveData
LiveData là một trình bao bọc có thể được sử dụng với bất kỳ dữ liệu nào, bao gồm cả các đối tượng triển khai Collections, chẳng hạn như List. Một đối tượng LiveData thường được lưu trữ trong một đối tượng ViewModel và được truy cập thông qua một phương thức getter, như đươc minh hoạ trong ví dụ sau:
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... }
Ban đầu, dữ liệu trong đối tượng LiveData chưa được đặt.
Bạn có thể đọc thêm về các lợi ích và cách sử dụng lớp ViewModel trong hướng dẫn về ViewModel.
Quan sát các đối tượng LiveData
Trong hầu hết trường hợp, phương thức onCreate() của thành phần ứng dụng là nơi phù hợp để bắt đầu quan sát một đối tượng LiveData vì các lý do sau:
- Để đảm bảo hệ thống không thực hiện các lệnh gọi thừa qua phương thức
onResume()của một hoạt động hoặc mảnh. - Để đảm bảo hoạt động hoặc mảnh có dữ liệu để có thể hiển thị ngay khi bắt đầu hoạt động. Ngay khi một thành phần ứng dụng vào trạng thái
STARTED, thành phần đó sẽ nhận được giá trị gần đây nhất từ các đối tượngLiveDatamà thành phần đó đang quan sát. Điều này chỉ xảy ra nếu đối tượngLiveDatacần quan sát đã được thiết lập.
Nhìn chung, LiveData chỉ phân phối thông tin cập nhật đến các trình quan sát đang hoạt động và chỉ khi dữ liệu có sự thay đổi. Hành vi này có một ngoại lệ là trình quan sát cũng sẽ nhận được thông tin cập nhật khi thay đổi trạng thái từ không hoạt động sang đang hoạt động. Hơn nữa, nếu trình quan sát thay đổi trạng thái từ không hoạt động sang hoạt động lần thứ hai, thì trình quan sát sẽ chỉ nhận được nội dung cập nhật nếu giá trị đã thay đổi kể từ lần hoạt động gần đây nhất.
Mã mẫu sau đây minh hoạ cách bắt đầu quan sát một đối tượng 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); } }
Sau khi observe() được gọi và có nameObserver được chuyển dưới dạng thông số, onChanged() sẽ được gọi ngay lập để cung cấp tức giá trị gần đây nhất được lưu trữ trong mCurrentName.
Nếu đối tượng LiveData không đặt giá trị trong mCurrentName, thì onChanged() sẽ không được gọi.
Cập nhật đối tượng DataData
LiveData không có phương pháp công khai để cập nhật dữ liệu đã lưu trữ. Lớp MutableLiveData sẽ hiển thị công khai phương thức setValue(T) và postValue(T). Bạn phải sử các phương thức này nếu cần chỉnh sửa giá trị được lưu trữ trong đối tượng LiveData. Thông thường, MutableLiveData được sử dụng trong ViewModel và sau đó ViewModel chỉ hiển thị các đối tượng LiveData không thể thay đổi cho trình quan sát.
Sau khi thiết lập mối quan hệ với trình quan sát, bạn có thể cập nhật giá trị của đối tượng LiveData (như được minh họa trong ví dụ sau) để kích hoạt tất cả trình quan sát khi người dùng nhấn vào một nút:
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); } });
Trong ví dụ, việc gọi setValue(T) sẽ khiến trình quan sát gọi phương thức onChanged() với giá trị John Doe. Ví dụ minh hoạ một thao tác nhấn nút, nhưng setValue() hoặcpostValue() có thể được gọi để cập nhật mName vì nhiều lý do, như để phản hồi một yêu cầu mạng hoặc việc hoàn tất tải cơ sở dữ liệu. Trong mọi trường hợp, lệnh gọi đếnsetValue() hoặcpostValue() sẽ kích hoạt trình quan sát và cập nhật giao diện người dùng.
Sử dụng DataData với Room
Thư viện lưu trữ Room hỗ trợ các truy vấn có thể quan sát và trả về các đối tượng LiveData.
Các truy vấn có thể quan sát được viết như một phần của một Đối tượng truy cập cơ sở dữ liệu (DAO).
Room tạo ra tất cả mã cần thiết để cập nhật đối tượng LiveData khi cập nhật một cơ sở dữ liệu. Mã được tạo này sẽ chạy truy vấn không đồng bộ trên một luồng chạy nền (background thread) khi cần. Mẫu này rất hữu ích trong việc giữ cho dữ liệu hiển thị trên giao diện người dùng đồng bộ hoá với dữ liệu được lưu trữ trong cơ sở dữ liệu. Bạn có thể đọc thêm về Room và DAO trong phần Hướng dẫn về thư viện lưu trữ Room.
Sử dụng coroutine với LiveData
LiveData có hỗ trợ cho coroutine Kotlin. Để biết thêm thông tin, hãy xem phần Sử dụng coroutine Kotlin với Bộ thành phần cấu trúc Android.
LiveData trong cấu trúc ứng dụng
LiveData có thể nhận biết và tuân theo vòng đời của các thực thể như hoạt động và mảnh. Hãy sử dụng LiveData để giao tiếp giữa các chủ sở hữu vòng đời này và các đối tượng có vòng đời khác, chẳng hạn như đối tượng ViewModel.
Trách nhiệm chính của ViewModel là tải và quản lý dữ liệu liên quan đến giao diện người dùng, khiến lớp này trở thành một ứng viên tiềm năng để lưu giữ các đối tượng LiveData. Tạo các đối tượng LiveData trong ViewModel và sử dụng các đối tượng đó để hiển thị trạng thái cho lớp giao diện người dùng.
Các hoạt động và mảnh không được lưu giữ các bản sao LiveData vì vai trò của chúng là hiển thị dữ liệu chứ không phải trạng thái. Ngoài ra, việc không để cho hoạt động và mảnh lưu giữ dữ liệu cũng giúp bạn viết mã kiểm thử đơn vị dễ dàng hơn.
Bạn có thể muốn để các đối tượng LiveData hoat động trong lớp (class) của lớp (layer) dữ liệu, nhưng LiveData không được thiết kế để xử lý các luồng dữ liệu (streams of data) theo cách không đồng bộ. Mặc dù bạn có thể sử dụng phép biến đổi LiveData và MediatorLiveData để làm được điều này, nhưng phương pháp này có một số trở ngại: khả năng kết hợp các luồng dữ liệu (streams of data) rất hạn chế và tất cả đối tượng LiveData (bao gồm cả các đối tượng được tạo bằng các phép biến đổi) sẽ được quan sát trên luồng chính (main thread). Mã dưới đây là một ví dụ cho thấy việc lưu giữ một LiveData trong Repository có thể chặn mất luồng chính (main thread):
Kotlin
class UserRepository { // DON'T DO THIS! LiveData objects should not live in the repository. fun getUsers(): LiveData<List<User>> { ... } fun getNewPremiumUsers(): LiveData<List<User>> { return getUsers().map { users -> // This is an expensive call being made on the main thread and may // cause noticeable jank in the UI! users .filter { user -> user.isPremium } .filter { user -> val lastSyncedTime = dao.getLastSyncedTime() user.timeCreated > lastSyncedTime } } }
Java
class UserRepository { // DON'T DO THIS! LiveData objects should not live in the repository. LiveData<List<User>> getUsers() { ... } LiveData<List<User>> getNewPremiumUsers() { return Transformations.map(getUsers(), // This is an expensive call being made on the main thread and may cause // noticeable jank in the UI! users -> users.stream() .filter(User::isPremium) .filter(user -> user.getTimeCreated() > dao.getLastSyncedTime()) .collect(Collectors.toList())); } }
Nếu bạn cần sử dụng các luồng dữ liệu (streams of data) trong các lớp khác của ứng dụng, hãy sử dụng Luồng Kotlin, sau đó chuyển đổi chúng sang LiveData trong ViewModel bằng asLiveData().
Hãy tìm hiểu thêm về cách sử dụng Flow Kotlin với LiveData trong lớp học lập trình này.
Đối với các cơ sở mã được tạo bằng Java, hãy cân nhắc sử dụng Trình thực thi cùng với lệnh gọi lại hoặc RxJava.
Mở rộng LiveData
LiveData sẽ coi trạng thái của trình quan sát là đang hoạt động nếu vòng đời của trình quan sát đó ở trạng thái STARTED hoặc RESUMED. Mã mẫu sau đây minh hoạ cách mở rộng lớp 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); } }
Việc triển khai trình nghe giá trong ví dụ này gồm có các phương thức quan trọng sau:
- Phương thức
onActive()được gọi khi đối tượngLiveDatacó một trình quan sát đang hoạt động. Điều này nghĩa là bạn cần bắt đầu quan sát các thông tin cập nhật về giá cổ phiếu từ phương pháp này. - Phương thức
onInactive()sẽ được gọi khi đối tượngLiveDatakhông có người quan sát nào đang hoạt động. Vì không có người quan sát nào đang nghe nên không cần phải tiếp tục kết nối với dịch vụStockManager. - Phương thức
setValue(T)sẽ cập nhật giá trị của thực thểLiveDatavà thông báo cho mọi trình quan sát đang hoạt động về thay đổi đó.
Bạn có thể sử dụng lớp StockLiveData như sau:
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(getViewLifecycleOwner(), price -> { // Update the UI. }); } }
Phương thức observe() sẽ chuyển LifecycleOwner liên kết với chế độ xem của mảnh dưới dạng đối số đầu tiên. Điều đó cho thấy trình quan sát này phụ thuộc vào đối tượng Lifecycle liên kết với chủ sở hữu, nghĩa là:
- Nếu đối tượng
Lifecyclekhông ở trạng thái đang hoạt động, thì trình quan sát sẽ không được gọi ngay cả khi giá trị thay đổi. - Sau khi đối tượng
Lifecyclebị huỷ, trình quan sát sẽ tự động bị xoá.
Thực tế là các đối tượng LiveData có thể nhận biết được vòng đời, nghĩa là bạn có thể chia sẻ các đối tượng đó giữa nhiều hoạt động, mảnh và dịch vụ. Để đơn giản hoá ví dụ này, bạn có thể triển khai lớp LiveData dưới dạng singleton như sau:
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); } }
Và bạn có thể sử dụng đoạn mã này trong mảnh như sau:
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. }); } }
Nhiều mảnh và hoạt động có thể quan sát thực thể MyPriceListener.
LiveData chỉ kết nối với dịch vụ hệ thống nếu một hoặc nhiều dịch vụ trong số đó hiển thị và đang hoạt động.
Biến đổi LiveData
Bạn nên thay đổi giá trị lưu trữ trong đối tượng LiveData trước khi gửi đối tượng này cho trình quan sát, hoặc có thể bạn sẽ cần trả về một thực thể LiveData khác dựa trên giá trị của một thực thể khác. Gói Lifecycle cung cấp lớp Transformations, bao gồm các phương thức trợ giúp để hỗ trợ cho các trường hợp này.
Transformations.map()- Áp dụng một hàm trên giá trị được lưu trữ trong đối tượng
LiveDatavà áp dụng kết quả xuôi dòng.
Kotlin
val userLiveData: LiveData<User> = UserLiveData() val userName: LiveData<String> = userLiveData.map { user -> "${user.name} ${user.lastName}" }
Java
LiveData<User> userLiveData = ...; LiveData<String> userName = Transformations.map(userLiveData, user -> { user.name + " " + user.lastName });
Transformations.switchMap()- Tương tự như
map(), áp dụng một hàm cho giá trị được lưu trữ trong đối tượngLiveData, mở gói và gửi kết quả đi xuôi chiều. Hàm được chuyển đếnswitchMap()phải trả về một đối tượngLiveData, như được minh hoạ trong ví dụ sau:
Kotlin
private fun getUser(id: String): LiveData<User> { ... } val userId: LiveData<String> = ... val user = userId.switchMap { id -> getUser(id) }
Java
private LiveData<User> getUser(String id) { ...; } LiveData<String> userId = ...; LiveData<User> user = Transformations.switchMap(userId, id -> getUser(id) );
Bạn có thể sử dụng các phép biến đổi để truyền thông tin trong suốt vòng đời của trình quan sát. Các phép biến đổi sẽ không được tính trừ khi có một trình quan sát đang xem đối tượng LiveData được trả về. Do các phép biến đổi được tính toán từng phần, nên hoạt động liên quan đến vòng đời sẽ ngầm được chuyển xuống mà không đòi hỏi các lệnh gọi hoặc phần phụ thuộc rõ ràng khác.
Nếu cho rằng bạn cần có một đối tượng Lifecycle bên trong đối tượng ViewModel, phép biến đổi có thể là một giải pháp tốt hơn. Ví dụ, giả sử bạn có một thành phần giao diện người dùng chấp nhận một địa chỉ và trả về mã bưu chính cho địa chỉ đó. Bạn có thể triển khai hàm ViewModel đơn thuần cho thành phần này như được minh hoạ bằng mã mẫu sau:
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); } }
Sau đó, thành phần giao diện người dùng cần huỷ đăng ký khỏi đối tượng LiveData trước đó và đăng ký bản sao mới mỗi khi thành phần này gọi getPostalCode(). Ngoài ra, nếu thành phần giao diện người dùng này được tạo lại, thì thành phần này sẽ kích hoạt một lệnh gọi khác đến phương thức repository.getPostCode() thay vì sử dụng kết quả của lệnh gọi trước đó.
Thay vào đó, bạn có thể triển khai quá trình tra cứu mã bưu chính dưới dạng một lượt chuyển đổi địa chỉ nhập vào, như trong ví dụ sau:
Kotlin
class MyViewModel(private val repository: PostalCodeRepository) : ViewModel() { private val addressInput = MutableLiveData<String>() val postalCode: LiveData<String> = addressInput.switchMap { 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); } }
Trong trường hợp này, trường postalCode được xem là sự biến đổi của addressInput. Miễn là ứng dụng của bạn có một trình quan sát đang hoạt động liên kết với trường postalCode, giá trị của trường đó sẽ được tính toán lại và truy xuất bất cứ khi nào addressInput thay đổi.
Cơ chế này cho phép các cấp thấp hơn của ứng dụng tạo các đối tượng LiveData được tính toán từng phần theo yêu cầu. Đối tượng ViewModel có thể dễ dàng lấy thông tin tham chiếu đến các đối tượng LiveData và sau đó xác định các quy tắc biến đổi ở trên các đối tượng đó.
Tạo các phép biến đổi mới
Có nhiều phép biển đổi cụ thể khác nhau có thể hữu ích trong ứng dụng của bạn, nhưng chúng không được cung cấp theo mặc định. Để triển khai phép biến đổi của mình, bạn có thể sử dụng lớp MediatorLiveData để nghe các đối tượng LiveData khác và xử lý các sự kiện do các đối tượng đó tạo ra. MediatorLiveData truyền chính xác trạng thái của lớp con này đến đối tượng LiveData nguồn. Để tìm hiểu thêm về mẫu này, hãy xem tài liệu tham khảo của lớp Transformations.
Hợp nhất nhiều nguồn LiveData
MediatorLiveData là một lớp con của LiveData cho phép bạn hợp nhất nhiều nguồn LiveData. Sau đó, trình quan sát các đối tượng MediatorLiveData sẽ được kích hoạt bất cứ khi nào có một đối tượng nguồn LiveData nguyên gốc thay đổi.
Ví dụ, nếu có một đối tượng LiveData trong giao diện người dùng có thể được cập nhật từ cơ sở dữ liệu cục bộ hoặc mạng, thì bạn có thể thêm các nguồn sau vào đối tượng MediatorLiveData:
- Đối tượng
LiveDataliên kết với dữ liệu được lưu trữ trong cơ sở dữ liệu. - Đối tượng
LiveDataliên kết với dữ liệu truy cập từ mạng.
Chỉ cần quan sát đối tượng MediatorLiveData để hoạt động của bạn nhận được thông tin cập nhật từ cả hai nguồn. Để biết ví dụ chi tiết, hãy xem Phụ lục: hiển thị trạng thái mạng trong mục Hướng dẫn về cấu trúc ứng dụng.
Tài nguyên khác
Để tìm hiểu thêm về lớp LiveData, hãy tham khảo các tài nguyên sau.
Mẫu
- Sunflower, một ứng dụng minh hoạ giới thiệu các phương pháp tốt nhất cho Thành phần cấu trúc
Lớp học lập trình
- Room Android có Chế độ xem (Java) (Kotlin)
- Tìm hiểu về các coroutine nâng cao với Kotlin Flow và LiveData
Blog
- ViewModel và LiveData: Mẫu + Mô hình phản tác dụng
- LiveData ngoài ViewModel — Các mẫu phản ứng sử dụng Phép biến đổi và MediatorLiveData
- LiveData có SnackBar (Thanh thông báo nhanh), Điều hướng và các sự kiện khác (trường hợp SingleLiveEvent)
Video
Đề xuất cho bạn
- Lưu ý: văn bản có đường liên kết sẽ hiện khi JavaScript tắt
- Sử dụng coroutine của Kotlin với các thành phần nhận biết vòng đời
- Điều khiển vòng đời bằng các thành phần nhận biết vòng đời
- Kiểm thử việc triển khai Phân trang (Paging)