ความแตกต่างของ setValue () & postValue () ใน MutableLiveData


119

MutableLiveDataมีสองวิธีที่ทำให้ค่าการเปลี่ยนแปลงของความเป็น แต่อะไรคือความแตกต่างระหว่างsetValue()& postValue()in MutableLiveData.

ฉันไม่พบเอกสารประกอบสำหรับสิ่งเดียวกัน

นี่คือคลาสMutableLiveDataของ 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);
    }
}

คำตอบ:


198

อ้างอิงจากเอกสารประกอบ:

setValue () :

ตั้งค่า หากมีผู้สังเกตการณ์ที่ใช้งานอยู่ค่าจะถูกส่งไปให้ ต้องเรียกวิธีนี้จากเธรดหลัก

postValue () :

โพสต์งานไปยังเธรดหลักเพื่อกำหนดค่าที่กำหนด หากคุณเรียกวิธีนี้หลายครั้งก่อนที่เธรดหลักจะเรียกใช้งานที่โพสต์ระบบจะส่งเฉพาะค่าสุดท้ายเท่านั้น

เพื่อสรุปความแตกต่างที่สำคัญคือ:

setValue()ต้องเรียกวิธีการจากเธรดหลัก แต่ถ้าคุณต้องการตั้งค่าจากเธรดพื้นหลังpostValue()ควรใช้


"เฉพาะค่าสุดท้ายเท่านั้นที่จะถูกส่งไป" ฉันไม่สามารถแน่ใจได้โดยการอ่านรหัส ดังนั้นดูเหมือนว่าเมื่อเธรดแรกเกี่ยวกับบล็อกที่ซิงโครไนซ์ด้านในภายใน postValue () หน้าต่าง CPU ถัดไปอาจถูกกำหนดให้กับเธรด 2 ซึ่งกำลังโพสต์ค่าอื่น จากนั้นเธรด 2 สามารถดำเนินการบล็อกที่ซิงโครไนซ์ให้เสร็จสมบูรณ์และตัวกำหนดตารางเวลาจะให้หน้าต่างเธรดแรกรันตัวเอง ตอนนี้มันเขียนทับสิ่งที่เธรด 2 เขียนไปแล้ว เป็นไปได้หรือไม่
stdout

109

คำตอบทั้งหมดข้างต้นถูกต้อง แต่ความแตกต่างที่สำคัญอีกประการหนึ่ง ถ้าคุณโทรpostValue()บนสนามที่มีผู้สังเกตการณ์ไม่มีและหลังจากที่คุณโทรหาคุณไม่ได้รับค่าที่คุณตั้งอยู่ในgetValue() postValue()ดังนั้นโปรดใช้ความระมัดระวังหากคุณทำงานในเธรดเบื้องหลังโดยไม่มีผู้สังเกตการณ์


4
หวังว่าฉันจะโหวตเพิ่มเป็นสามเท่า! จากสิ่งนี้ดูเหมือนว่าควรใช้setValue()หากเป็นไปได้และใช้ "postValue ()" อย่างระมัดระวังเมื่อจำเป็นเท่านั้น ขอบคุณ
jungledev

1
ไม่นี่ไม่ใช่วิธีที่ "ดีที่สุด" หากคุณทำงานกับ LiveData จากเธรดพื้นหลังคุณควรใช้ postValue นอกจากนี้ในส่วนประกอบวงจรการใช้งานเวอร์ชันล่าสุดได้รับการแก้ไขแล้ว ...
ห 1

"นอกจากนี้ในส่วนประกอบวงจรการใช้งานเวอร์ชันล่าสุดจะได้รับการแก้ไข ... คุณมีข้อมูลเพิ่มเติมเกี่ยวกับเรื่องนี้หรือไม่? ขอบคุณ
Chris Nevill

1
ฉันทำการทดสอบบางอย่างและดูเหมือนว่าด้วย lib เวอร์ชันล่าสุดทุกอย่างทำงานได้ตามที่ควร
w201

คุณช่วยแสดงรหัสด้านบนอย่างเป็นรูปธรรมได้ไหม ถ้าใน ViewModel ฉันใช้งานเหมือนnoObserveLiveData.postValue("sample")ในกิจกรรมเมื่อฉันใช้ getValue เช่นviewModel.noObserveLiveData.getValueคุณหมายถึงมันไม่ใช่ค่าที่ฉันตั้งไว้ใน postValue () ("ตัวอย่าง") หรือไม่
กิโลวัตต์

17

setValue()ถูกเรียกโดยตรงจากเธรดผู้โทรแจ้งผู้สังเกตการณ์พร้อมกันและเปลี่ยนLiveDataค่าทันที สามารถเรียกได้จาก MainThread เท่านั้น
postValue()ใช้ภายในสิ่งนี้new Handler(Looper.mainLooper()).post(() -> setValue())ดังนั้นมันจึงทำงานsetValueผ่านHandlerใน MainThread สามารถเรียกได้จากทุกหัวข้อ


11

setValue()

ตั้งค่า หากมีผู้สังเกตการณ์ที่ทำงานอยู่ค่าจะถูกส่งไปให้

วิธีการนี้จะต้องถูกเรียกจากหัวข้อหลัก

postValue

หากคุณต้องการตั้งค่าจากเธรดพื้นหลังคุณสามารถใช้ postValue(Object)

โพสต์งานไปยังเธรดหลักเพื่อกำหนดค่าที่กำหนด

หากคุณเรียกวิธีนี้หลายครั้งก่อนที่เธรดหลักจะเรียกใช้งานที่โพสต์ระบบจะส่งเฉพาะค่าสุดท้ายเท่านั้น


7

นี่ไม่ใช่คำตอบโดยตรงสำหรับปัญหาข้างต้น คำตอบจากSagarและw201นั้นยอดเยี่ยมมาก แต่หลักการง่ายๆที่ฉันใช้ใน ViewModels สำหรับ MutableLiveData คือ:

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);
}

แทนที่mutValด้วยค่าที่คุณต้องการ


ดีฉันชอบสิ่งนี้ ใน Kotlin ฉันได้สร้างส่วนขยายที่ห่อหุ้มการอัปเดตอัจฉริยะดังนั้นการอัปเดตมูลค่ามากมายในแอปของฉันจึงเป็นการโทรเพียงครั้งเดียวที่สอดคล้องกัน
19Craig

4

setValue()ต้องเรียกวิธีการจากเธรดหลัก postValue()หากคุณจำเป็นต้องตั้งค่าจากด้ายพื้นหลังคุณสามารถใช้

เพิ่มเติมที่นี่ .


0

ในแอปของเราเราได้ใช้ LiveData เดียวที่มีข้อมูลสำหรับการดูหลายครั้งในกิจกรรม / หน้าจอ โดยทั่วไปไม่มีชุดข้อมูลสำหรับไม่มีมุมมอง สิ่งนี้ทำให้เรามีปัญหาเล็กน้อยเนื่องจากวิธี postData ออกแบบมาสำหรับ และเรามีออบเจ็กต์สถานะใน LD ที่บ่งบอกถึงมุมมองที่ต้องอัปเดต

LD จึงมีลักษณะดังนี้:

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

มีสองมุมมอง (view_1 และ view_2) ที่ต้องได้รับการอัปเดตเมื่อมีเหตุการณ์หนึ่งเกิดขึ้น. หมายความว่าพวกเขาควรได้รับการแจ้งเตือนพร้อมกันเมื่อมีเหตุการณ์เกิดขึ้น ฉันเรียกว่า:

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

สิ่งนี้จะไม่ได้ผลด้วยเหตุผลที่เรารู้

สิ่งที่ฉันเข้าใจก็คือโดยพื้นฐานแล้ว LD หนึ่งตัวควรแสดงเพียงมุมมองเดียว จากนั้นไม่มีโอกาสที่คุณจะต้องเรียก postData () สองครั้งติดต่อกัน แม้ว่าคุณจะโทรหาวิธีที่ postData จัดการให้คุณก็เป็นสิ่งที่คุณคาดหวังได้เช่นกัน (แสดงข้อมูลล่าสุดให้คุณเห็น) ทุกอย่างเข้าที่ได้ดี

หนึ่ง LD -> หนึ่งมุมมอง สมบูรณ์แบบ

หนึ่ง LD -> หลายมุมมองอาจมีพฤติกรรมแปลก ๆ

โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.