เหตุใดจึงมีคลาสย่อย MutableLiveData ของ LiveData แยกต่างหาก


96

ดูเหมือนว่าจะMutableLiveDataแตกต่างจากLiveDataการทำให้setValue()และpostValue()วิธีการสาธารณะเท่านั้นในขณะที่LiveDataพวกเขาได้รับการคุ้มครอง

มีเหตุผลอะไรบ้างในการสร้างคลาสแยกต่างหากสำหรับการเปลี่ยนแปลงนี้และไม่เพียงกำหนดวิธีการเหล่านั้นให้เป็นแบบสาธารณะในLiveDataตัวเอง

โดยทั่วไปแล้วรูปแบบของการสืบทอด (การเพิ่มการมองเห็นของวิธีการบางอย่างเป็นการเปลี่ยนแปลงเพียงอย่างเดียว) การปฏิบัติที่รู้จักกันดีและมีสถานการณ์ใดบ้างที่อาจเป็นประโยชน์ (สมมติว่าเราสามารถเข้าถึงรหัสทั้งหมดได้)


10
เป็นการตัดสินใจในการออกแบบ LiveDataไม่เปลี่ยนรูปเนื่องจากไคลเอนต์ไม่สามารถเปลี่ยนสถานะภายในได้ดังนั้นเธรดปลอดภัย
Blackbelt

คำตอบ:


138

ในLiveData - เอกสารนักพัฒนาซอฟต์แวร์ Androidคุณสามารถเห็นได้ว่าสำหรับLiveData, setValue()และpostValue()วิธีการไม่ได้เป็นของประชาชน

ในขณะที่ในMutableLiveData - เอกสารนักพัฒนาซอฟต์แวร์ Androidคุณสามารถเห็นว่าMutableLiveDataขยายLiveDataภายในและยังมีสองวิธีมหัศจรรย์ของLiveDataเป็นต่อสาธารณะที่มีอยู่ในนี้และพวกเขาจะ&setValue()postValue()

setValue(): ตั้งค่าและส่งค่าไปสังเกตการณ์ที่ใช้งานทั้งหมดจะต้องถูกเรียกจากหัวข้อหลัก

postValue(): โพสต์งานไปที่หัวข้อหลักที่จะคุ้มค่าการลบล้างการตั้งค่าโดยsetValue()จะต้องเรียกจากด้ายพื้นหลัง

ดังนั้นLiveDataเป็นไม่เปลี่ยนรูป MutableLiveDataเป็นLiveDataสิ่งที่เปลี่ยนแปลงได้และปลอดภัยต่อเธรด


36
ไม่ใช่ว่า LiveData จะไม่เปลี่ยนรูปจริง ๆ เพียง แต่ไม่สามารถแก้ไขได้นอกคลาส ViewModel คลาส ViewModel สามารถแก้ไขได้ตามที่ต้องการ (เช่นตัวจับเวลา ViewModel) คุณจะใช้ MutableLiveData ถ้าคุณต้องการแก้ไขนอกคลาส ViewModel
Elliptica

2
ลองใช้สถานการณ์นี้เป็นแอปที่มีรูปแบบพื้นที่เก็บข้อมูล (เซิร์ฟเวอร์ + ห้อง) โดยที่ห้องเป็นแหล่งความจริงเดียว แอปรับข้อมูลจากห้องเท่านั้นในขณะที่ Room ได้รับการอัปเดตจากเซิร์ฟเวอร์ mutableLiveData เป็นสิ่งที่ต้องใช้เนื่องจากสามารถใช้ข้อมูลจากห้องอัพเดตเซิร์ฟเวอร์หรือ LiveData ได้หรือไม่
Dr4ke the b4dass

5
LiveData เป็นนามธรรมดังนั้นคุณจึงไม่สามารถสร้างวัตถุ LiveData ได้โดยตรงโดยไม่ต้องขยาย MutableLiveData ขยาย LiveData
Serdar Samancıoğlu

1
ลิงก์ไปยัง LiveData และ MutableLiveData โดยตรงไปยังเอกสารที่เลิกใช้แล้ว เหตุใดเมื่อฉันแนะนำการแก้ไขด้วยลิงก์จริงจึงถูกปฏิเสธ
Daniel

1
@ แดเนียลไม่แน่ใจว่าเหตุใดจึงถูกปฏิเสธโดยผู้ตรวจสอบรายอื่นในคิวการตรวจสอบ ฉันได้อนุมัติการเปลี่ยนแปลงแล้วขอบคุณ! :)
Sneh Pandya

10

นี่คือMutableLiveData.javaไฟล์ทั้งหมด:

package androidx.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);
    }
}

ใช่แล้วความแตกต่างมาจากการเผยแพร่postValueและsetValueเผยแพร่ต่อสาธารณะเท่านั้น

กรณีการใช้งานอย่างหนึ่งที่ฉันจำได้จากหัวของฉันคือการห่อหุ้มโดยใช้Backing Propertyใน Kotlin คุณสามารถเปิดเผยLiveDataกับ Fragment / Activity (UI Controller) ของคุณได้แม้ว่าคุณจะมีMutableLiveDataไว้สำหรับจัดการในViewModelคลาส

    class TempViewModel : ViewModel() {
        ...
        private val _count = MutableLiveData<Int>()
        val count: LiveData<Int>
            get() = _count
        public fun incrementCount() = _count.value?.plus(1)
        ...
    }

วิธีนี้ UI Controller ของคุณจะสามารถสังเกตค่าโดยไม่สามารถแก้ไขได้ เห็นได้ชัดว่า UI ควบคุมของคุณสามารถแก้ไขค่าใช้วิธีการของประชาชน เช่นTempViewModelincrementCount()

หมายเหตุ : เพื่อชี้แจงความสับสนที่เปลี่ยนแปลงไม่ได้ / ไม่เปลี่ยนรูป -

data class User(var name: String, var age: Int)

class DemoLiveData: LiveData<User>()

var demoLiveData: LiveData<User>? = DemoLiveData()

fun main() {
    demoLiveData?.value = User("Name", 23) // ERROR
    demoLiveData?.value?.name = "Name" // NO ERROR
    demoLiveData?.value?.age = 23  // NO ERROR
}

คืออะไร_score?
IgorGanapolsky

0

MutableLiveData ขยายจาก LiveData วิธีการป้องกันของ LiveData สามารถแก้ไขได้ด้วยตนเองหรือคลาสย่อยเท่านั้น ดังนั้นในกรณีนี้ MutableLiveData ซึ่งเป็นคลาสย่อยของ LiveData สามารถเข้าถึงวิธีการป้องกันเหล่านี้ได้

สิ่งที่คุณต้องการทำคือสังเกตจากอินสแตนซ์และดูว่ามีการเปลี่ยนแปลงหรือไม่ แต่ในขณะเดียวกันคุณก็ไม่ต้องการให้ "บุคคลภายนอก" ใด ๆ มาเปลี่ยนแปลงอินสแตนซ์นั้น ในแง่หนึ่งสิ่งนี้ทำให้เกิดปัญหาเนื่องจากคุณต้องการให้วัตถุที่เป็นและเปลี่ยนแปลงได้เพื่ออัปเดตสถานะใหม่และไม่สามารถเปลี่ยนแปลงได้เพื่อให้แน่ใจว่าไม่มีใครที่ไม่ควรอัปเดตอินสแตนซ์นี้ คุณลักษณะทั้งสองนี้ขัดแย้งกัน แต่สามารถแก้ไขได้โดยการสร้างเลเยอร์พิเศษ

ดังนั้นสิ่งที่คุณทำคือขยายคลาส LiveData ของคุณด้วยคลาสที่สามารถเข้าถึงเมธอดได้ เลเยอร์ย่อยในกรณีนี้คือ MutableLiveData สามารถเข้าถึงวิธีการป้องกันของพาเรนต์ (/ super) ได้

ตอนนี้คุณเริ่มสร้างอินสแตนซ์และสร้างอินสแตนซ์ผู้สังเกตการณ์ของ MutableLiveData ในเวลาเดียวกันคุณสร้างอินสแตนซ์ LiveData โดยอ้างถึงอินสแตนซ์เดียวกันนี้ เนื่องจาก MutableLiveData ขยาย LiveData อินสแตนซ์ MutableLiveData ใด ๆ จึงเป็นออบเจ็กต์ LiveData ดังนั้นจึงสามารถอ้างอิงได้โดยตัวแปร LiveData

ตอนนี้เคล็ดลับเกือบเสร็จแล้ว คุณแสดงเฉพาะอินสแตนซ์ LiveData เท่านั้นไม่มีใครสามารถใช้วิธีการป้องกันและไม่สามารถส่งไปยังขั้นสูงได้ (อาจจะในเวลาคอมไพล์ แต่จะไม่ทำงาน: ข้อผิดพลาด RunTime) และคุณเก็บอินสแตนซ์คลาสย่อยจริงไว้เป็นส่วนตัวดังนั้นจึงสามารถเปลี่ยนแปลงได้โดยผู้ที่เป็นเจ้าของอินสแตนซ์เท่านั้นโดยใช้วิธีการของอินสแตนซ์

//create instance of the sub class and keep this private
private val _name: MutableLiveData<String> = MutableLiveData<String>()
//create an instance of the super class referring to the same instance
val name: LiveData<String> = _name
//assign observer to the super class, being unable to change it
name.value.observe(.....)

ตอนนี้ซุปเปอร์คลาสจะแจ้งเตือนเมื่อมีการใช้การเปลี่ยนแปลงใด ๆ

//change the instance by using the sub class
_name.postValue(...)
//or _name.setValue(...)

Blockquote โดยทั่วไปแล้วรูปแบบของการสืบทอด (การเพิ่มการมองเห็นของวิธีการบางอย่างเป็นการเปลี่ยนแปลงเพียงอย่างเดียว) การปฏิบัติที่เป็นที่รู้จักกันดีและมีสถานการณ์ใดบ้างที่อาจเป็นประโยชน์ (สมมติว่าเราสามารถเข้าถึงรหัสทั้งหมดได้)

ใช่มันค่อนข้างเป็นที่รู้จักกันดีและสิ่งที่อธิบายไว้ข้างต้นเป็นสถานการณ์ทั่วไป ลบรูปแบบผู้สังเกตการณ์และทำให้เป็น set / get form ก็จะได้รับประโยชน์มากพอ ๆ กับมัน ขึ้นอยู่กับว่าคุณนำไปใช้ที่ใดไม่มีกฎทองในตอนท้าย

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