Sự khác biệt của setValue () & postValue () trong MutableLiveData


104

Có hai cách tạo ra giá trị thay đổi của MutableLiveData. Nhưng sự khác biệt giữa setValue()& postValue()trong là gì MutableLiveData.

Tôi không thể tìm thấy tài liệu cho giống nhau.

Đây là lớp MutableLiveDatacủa Android.

package android.arch.lifecycle;

/**
 * {@link LiveData} which publicly exposes {@link #setValue(T)} and {@link #postValue(T)} method.
 *
 * @param <T> The type of data hold by this instance
 */
@SuppressWarnings("WeakerAccess")
public class MutableLiveData<T> extends LiveData<T> {
    @Override
    public void postValue(T value) {
        super.postValue(value);
    }

    @Override
    public void setValue(T value) {
        super.setValue(value);
    }
}

Câu trả lời:


177

Dựa trên tài liệu:

setValue () :

Đặt giá trị. Nếu có những người quan sát tích cực, giá trị sẽ được gửi đến họ. Phương thức này phải được gọi từ luồng chính.

postValue () :

Đăng một nhiệm vụ lên một luồng chính để đặt giá trị đã cho. Nếu bạn đã gọi phương thức này nhiều lần trước khi luồng chính thực thi một tác vụ đã đăng, thì chỉ giá trị cuối cùng mới được gửi đi.

Tóm lại, sự khác biệt chính sẽ là:

setValue()phương thức phải được gọi từ luồng chính. Nhưng nếu bạn cần đặt một giá trị từ một chuỗi nền, postValue()nên được sử dụng.


"chỉ giá trị cuối cùng mới được gửi đi". Tôi không thể chắc chắn về nó bằng cách đọc mã. Vì vậy, có vẻ như khi luồng đầu tiên sắp chạm vào khối đồng bộ bên trong bên trong postValue (), cửa sổ CPU tiếp theo có thể được cấp cho luồng 2 đang đăng một giá trị khác. Sau đó, luồng 2 có thể hoàn thành khối được đồng bộ hóa và bộ lập lịch cung cấp cho luồng đầu tiên một cửa sổ để tự chạy. Bây giờ, nó ghi đè những gì mà luồng 2 đã viết. Điều này có khả thi không?
stdout

93

Tất cả các câu trả lời trên đều đúng. Nhưng một điểm khác biệt quan trọng hơn. Nếu bạn gọi postValue()trên trường không có người quan sát và sau đó bạn gọi getValue(), bạn sẽ không nhận được giá trị mà bạn đã đặt postValue(). Vì vậy, hãy cẩn thận nếu bạn làm việc trong các luồng nền mà không có người quan sát.


3
Ước gì tôi có thể tăng gấp ba lần! Dựa trên điều này, có vẻ như tốt nhất là sử dụng setValue()nếu có thể và thận trọng sử dụng 'postValue ()', chỉ khi cần thiết. Cảm ơn
jungledev

1
Không, đây không phải là cách "tốt nhất". Nếu bạn làm việc với LiveData của mình từ luồng nền, bạn nên sử dụng postValue. Ngoài ra trong phiên bản mới nhất của các thành phần vòng đời, nó đã sửa ... có lẽ.
w201 14/1218

"Cũng có thể trong phiên bản mới nhất của các thành phần vòng đời, nó đã sửa ... có thể." Bạn có bất kỳ thông tin thêm về điều này? Cảm ơn
Chris Nevill

1
Tôi đã thực hiện một số thử nghiệm và có vẻ như với phiên bản mới nhất của lib, mọi thứ hoạt động như bình thường.
w201

Bạn có thể chỉ cho tôi đoạn mã cụ thể ở trên được không? Nếu Trong ViewModel, Tôi đã triển khai như noObserveLiveData.postValue("sample"), Trong Hoạt động, khi tôi sử dụng getValue như viewModel.noObserveLiveData.getValueBạn có nghĩa là Nó không phải là giá trị mà tôi đặt trong postValue () ("sample")?
kwmt

13

setValue()được gọi trực tiếp từ luồng người gọi, đồng bộ thông báo cho người quan sát và thay đổi LiveDatagiá trị ngay lập tức. Nó chỉ có thể được gọi từ MainThread.
postValue()sử dụng bên trong một cái gì đó như thế này new Handler(Looper.mainLooper()).post(() -> setValue()), vì vậy nó chạy setValuequa HandlerMainThread. Nó có thể được gọi từ bất kỳ chủ đề nào.


10

setValue()

Đặt giá trị. Nếu có những người quan sát tích cực, giá trị sẽ được gửi đến họ.

Phương thức này phải được gọi từ luồng chính .

postValue

Nếu bạn cần đặt giá trị từ một chuỗi nền, bạn có thể sử dụng postValue(Object)

Đăng một nhiệm vụ lên một luồng chính để đặt giá trị đã cho.

Nếu bạn đã gọi phương thức này nhiều lần trước khi luồng chính thực thi một tác vụ đã đăng, thì chỉ giá trị cuối cùng mới được gửi đi.


5

Đây không phải là câu trả lời trực tiếp cho vấn đề trên. Câu trả lời từ Sagarw201 thật tuyệt vời. Nhưng một quy tắc đơn giản mà tôi sử dụng trong ViewModels cho MutableLiveData là:

private boolean isMainThread() {
    return Looper.myLooper() == Looper.getMainLooper();
}

private MutableLiveData<Boolean> mutVal = new MutableLiveData<>(false);
public LiveData<Boolean> getMutVal() { return this.mutVal;  }
public void setMutVal(boolean val) {
    if (isMainThread()) mutVal.setValue(val);
    else mutVal.postValue(val);
}

Thay thế mutValbằng giá trị mong muốn của bạn.


Tốt, tôi thích điều này. Trong Kotlin, tôi đã tạo một tiện ích mở rộng đóng gói bản cập nhật thông minh để nhiều bản cập nhật giá trị xuyên suốt ứng dụng của tôi là một lệnh gọi nhất quán duy nhất.
19Craig

4

setValue()phương thức phải được gọi từ luồng chính. Nếu bạn cần đặt giá trị từ một chuỗi nền, bạn có thể sử dụng postValue().

Thêm ở đây .


0

Trong ứng dụng của chúng tôi, chúng tôi đã sử dụng một LiveData chứa dữ liệu cho nhiều chế độ xem trong một hoạt động / màn hình. Về cơ bản N không có bộ dữ liệu cho N không có chế độ xem. Điều này gây khó khăn cho chúng tôi một chút vì cách postData được thiết kế. Và chúng tôi có đối tượng trạng thái trong LD truyền tải để xem chế độ xem nào cần được cập nhật.

vì vậy LD trông như thế này:

LD {
   state (view_1, view_2, view_3 …),
   model_that_contains_data_of_all_views
}

Có một số chế độ xem (view_1 và view_2) phải được cập nhật khi một sự kiện xảy ra..có nghĩa là chúng sẽ được thông báo cùng lúc khi sự kiện xảy ra. Vì vậy, tôi đã gọi:

postData(LD(view_1, data))
postData(LD(view_2, data)

Điều này sẽ không hoạt động vì những lý do mà chúng tôi biết.

Điều tôi hiểu là về cơ bản một LD chỉ nên đại diện cho một chế độ xem. Sau đó, không có khả năng bạn phải gọi postData () hai lần liên tiếp. Ngay cả khi bạn gọi, cách postData xử lý nó cho bạn là những gì bạn cũng mong đợi (hiển thị dữ liệu mới nhất cho bạn trong chế độ xem). Tất cả mọi thứ rơi vào đúng vị trí.

Một LD -> một Chế độ xem. HOÀN HẢO

Một LD -> nhiều lượt xem CÓ THỂ LÀ HÀNH VI CỦA WEIRD

Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.