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
Observer
khi 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ượngObserver
nà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
Lifecycle
và 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
LiveData
bằng mẫu singleton để gói và chia sẻ các dịch vụ hệ thống trong ứng dụng. Đối tượngLiveData
sẽ 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ượngLiveData
thay đổi dữ liệu đã lưu giữ. Bạn thường tạo một đối tượngObserver
trong 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
Observer
vào đối tượngLiveData
bằ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ượngObserver
với đối tượngLiveData
để được thông báo về các thay đổi. Bạn thường đính kèm đối tượngObserver
trong 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ượngLiveData
mà thành phần đó đang quan sát. Điều này chỉ xảy ra nếu đối tượngLiveData
cầ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ượngLiveData
có 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ượngLiveData
khô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ểLiveData
và 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
Lifecycle
khô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
Lifecycle
bị 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
LiveData
và á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
LiveData
liên kết với dữ liệu được lưu trữ trong cơ sở dữ liệu. - Đối tượng
LiveData
liê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)