ภาพรวม LiveData   เป็นส่วนหนึ่งของ Android Jetpack

LiveData เป็นคลาสที่เก็บข้อมูลแบบสังเกตได้ LiveData แตกต่างจาก Observable ทั่วไปตรงที่ LiveData จะคำนึงถึงวงจร ซึ่งหมายความว่าจะเป็นไปตามวงจรของคอมโพเนนต์อื่นๆ ของแอป เช่น กิจกรรม ฟragment หรือบริการ การตรวจสอบนี้ช่วยให้มั่นใจได้ว่า LiveData จะอัปเดตเฉพาะเครื่องมือตรวจสอบคอมโพเนนต์แอปที่อยู่ในสถานะวงจรการทํางานที่ใช้งานอยู่เท่านั้น

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

คุณสามารถลงทะเบียนผู้สังเกตการณ์ที่จับคู่กับออบเจ็กต์ที่ใช้LifecycleOwner อินเทอร์เฟซ ความสัมพันธ์นี้ช่วยให้นำเครื่องมือตรวจสอบออกได้เมื่อสถานะของออบเจ็กต์ Lifecycle ที่เกี่ยวข้องเปลี่ยนไปเป็น DESTROYED ซึ่งจะเป็นประโยชน์อย่างยิ่งสําหรับกิจกรรมและข้อมูลโค้ดที่ฝังอยู่ เนื่องจากสามารถสังเกตออบเจ็กต์ LiveData ได้อย่างปลอดภัยและไม่ต้องกังวลเกี่ยวกับการรั่วไหล เนื่องจากระบบจะยกเลิกการติดตามกิจกรรมและข้อมูลโค้ดที่ฝังอยู่ทันทีเมื่อทำลายวงจรชีวิตของออบเจ็กต์

ดูข้อมูลเพิ่มเติมเกี่ยวกับวิธีใช้ LiveData ได้ที่ทํางานกับออบเจ็กต์ LiveData

ข้อดีของการใช้ LiveData

การใช้ LiveData มีข้อดีดังนี้

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

ทำงานกับออบเจ็กต์ LiveData

ทําตามขั้นตอนต่อไปนี้เพื่อทํางานกับออบเจ็กต์ LiveData

  1. สร้างอินสแตนซ์ของ LiveData เพื่อเก็บข้อมูลบางประเภท ซึ่งโดยปกติจะดำเนินการภายในชั้นเรียน ViewModel
  2. สร้างออบเจ็กต์ Observer ที่กําหนดวิธี onChanged() ซึ่งควบคุมสิ่งที่จะเกิดขึ้นเมื่อข้อมูลที่มีของออบเจ็กต์ LiveData เปลี่ยนแปลง โดยปกติแล้ว คุณจะต้องสร้างออบเจ็กต์ Observer ในตัวควบคุม UI เช่น กิจกรรมหรือแฟรกเมนต์
  3. แนบออบเจ็กต์ Observer กับออบเจ็กต์ LiveData โดยใช้เมธอด observe() เมธอด observe() ใช้ออบเจ็กต์ LifecycleOwner ซึ่งจะสมัครรับข้อมูลออบเจ็กต์ Observer กับออบเจ็กต์ LiveData เพื่อให้ได้รับการแจ้งเตือนเกี่ยวกับการเปลี่ยนแปลง โดยปกติแล้วคุณจะแนบออบเจ็กต์ Observer ในตัวควบคุม UI เช่น กิจกรรมหรือแฟรกเมนต์

เมื่อคุณอัปเดตค่าที่จัดเก็บไว้ในออบเจ็กต์ LiveData ระบบจะทริกเกอร์ผู้สังเกตการณ์ที่ลงทะเบียนไว้ทั้งหมด ตราบใดที่ LifecycleOwner ที่แนบมาอยู่ในสถานะ "ทำงานอยู่"

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

สร้างออบเจ็กต์ LiveData

LiveData คือ Wrapper ที่ใช้กับข้อมูลใดก็ได้ รวมถึงออบเจ็กต์ที่ใช้ Collections เช่น List โดยปกติแล้วออบเจ็กต์ LiveData จะเก็บไว้ในออบเจ็กต์ ViewModel และเข้าถึงผ่านเมธอด getter ดังที่แสดงในตัวอย่างต่อไปนี้

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...
}

ในช่วงแรก จะไม่มีการตั้งค่าข้อมูลในออบเจ็กต์ LiveData

อ่านข้อมูลเพิ่มเติมเกี่ยวกับประโยชน์และการใช้งานของคลาส ViewModel ได้ในคู่มือ ViewModel

สังเกตออบเจ็กต์ LiveData

ในกรณีส่วนใหญ่ วิธีการ onCreate() ของคอมโพเนนต์แอปคือจุดเริ่มต้นที่เหมาะสมในการสังเกตออบเจ็กต์ LiveData ด้วยเหตุผลต่อไปนี้

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

โดยทั่วไป LiveData จะส่งการอัปเดตเฉพาะเมื่อมีการเปลี่ยนแปลงข้อมูล และส่งไปยังผู้สังเกตการณ์ที่ใช้งานอยู่เท่านั้น ข้อยกเว้นของลักษณะการทํางานนี้คือ ผู้สังเกตการณ์จะได้รับข้อมูลอัปเดตด้วยเมื่อเปลี่ยนจากสถานะ "ไม่ได้ใช้งาน" เป็น "ใช้งานอยู่" นอกจากนี้ หากเครื่องมือตรวจสอบเปลี่ยนจาก "ไม่ทำงาน" เป็น "ทำงานอยู่" เป็นครั้งที่ 2 เครื่องมือจะได้รับการอัปเดตก็ต่อเมื่อค่ามีการเปลี่ยนแปลงนับตั้งแต่ที่ทำงานอยู่ครั้งล่าสุด

โค้ดตัวอย่างต่อไปนี้แสดงวิธีเริ่มสังเกตการณ์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);
    }
}

หลังจากเรียกใช้ observe() โดยส่ง nameObserver เป็นพารามิเตอร์แล้ว ระบบจะเรียกใช้ onChanged() ทันทีพร้อมระบุค่าล่าสุดที่จัดเก็บไว้ใน mCurrentName หากออบเจ็กต์ LiveData ไม่ได้ตั้งค่าใน mCurrentName ระบบจะไม่เรียกใช้ onChanged()

อัปเดตออบเจ็กต์ LiveData

LiveData ไม่มีวิธีการที่เผยแพร่ต่อสาธารณะเพื่ออัปเดตข้อมูลที่จัดเก็บไว้ คลาส MutableLiveData แสดงเมธอด setValue(T) และ postValue(T) แก่สาธารณะ และคุณต้องใช้เมธอดเหล่านี้หากต้องการแก้ไขค่าที่เก็บไว้ในออบเจ็กต์ LiveData โดยปกติแล้ว MutableLiveData จะใช้ใน ViewModel จากนั้น ViewModel จะแสดงเฉพาะออบเจ็กต์ LiveData ที่ไม่เปลี่ยนแปลงได้ต่อผู้สังเกตการณ์

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

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

การเรียก setValue(T) ในตัวอย่างนี้ส่งผลให้ผู้สังเกตการณ์เรียกใช้เมธอด onChanged() ด้วยค่า John Doe ตัวอย่างนี้แสดงการกดปุ่ม แต่อาจเรียก setValue() หรือ postValue() เพื่ออัปเดต mName ด้วยเหตุผลหลายประการ ซึ่งรวมถึงการตอบสนองต่อคําขอเครือข่ายหรือการโหลดฐานข้อมูลที่เสร็จสมบูรณ์ ในทุกกรณี การเรียก setValue() หรือ postValue() จะทริกเกอร์ผู้สังเกตการณ์และอัปเดต UI

ใช้ LiveData กับ Room

ไลบรารีการคงข้อมูล Room รองรับการค้นหาที่สังเกตได้ ซึ่งจะแสดงผลออบเจ็กต์ LiveData การค้นหาที่สังเกตได้จะเขียนขึ้นเป็นส่วนหนึ่งของออบเจ็กต์การเข้าถึงฐานข้อมูล (DAO)

Room จะสร้างโค้ดที่จำเป็นทั้งหมดเพื่ออัปเดตออบเจ็กต์ LiveData เมื่ออัปเดตฐานข้อมูล โค้ดที่สร้างขึ้นจะเรียกใช้การค้นหาแบบอะซิงโครนัสในเธรดเบื้องหลังเมื่อจำเป็น รูปแบบนี้มีประโยชน์ในการทำให้ข้อมูลที่แสดงใน UI ซิงค์กับข้อมูลที่จัดเก็บไว้ในฐานข้อมูล อ่านข้อมูลเพิ่มเติมเกี่ยวกับ Room และ DAO ได้ในคู่มือคลังถาวรของ Room

ใช้ Coroutine กับ LiveData

LiveData รองรับโคโริวทีนของ Kotlin ดูข้อมูลเพิ่มเติมได้ที่หัวข้อใช้โคโริวทีนของ Kotlin กับคอมโพเนนต์สถาปัตยกรรม Android

LiveData ในสถาปัตยกรรมของแอป

LiveData รับรู้วงจรของข้อมูลต่างๆ เช่น กิจกรรมและข้อมูล ใช้ LiveData เพื่อสื่อสารระหว่างเจ้าของวงจรเหล่านี้กับออบเจ็กต์อื่นๆ ที่มีอายุการใช้งานต่างกัน เช่น ออบเจ็กต์ ViewModel หน้าที่หลักของ ViewModel คือโหลดและจัดการข้อมูลที่เกี่ยวข้องกับ UI ซึ่งทำให้เหมาะอย่างยิ่งที่จะเก็บออบเจ็กต์ LiveData สร้างออบเจ็กต์ LiveData ใน ViewModel และใช้เพื่อแสดงสถานะต่อเลเยอร์ UI

กิจกรรมและฟragment ไม่ควรเก็บอินสแตนซ์ LiveData เนื่องจากบทบาทของกิจกรรมและฟragment คือการแสดงข้อมูล ไม่ใช่เก็บสถานะ นอกจากนี้ การที่กิจกรรมและฟragment ไม่มีการถือครองข้อมูลยังช่วยให้เขียนการทดสอบหน่วยได้ง่ายขึ้นด้วย

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

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

หากต้องการใช้สตรีมข้อมูลในเลเยอร์อื่นๆ ของแอป ให้พิจารณาใช้ Kotlin Flow แล้วแปลงเป็น LiveData ใน ViewModel โดยใช้ asLiveData() ดูข้อมูลเพิ่มเติมเกี่ยวกับการใช้ Kotlin Flow กับ LiveData ใน Codelab นี้ สําหรับโค้ดเบสที่สร้างด้วย Java ให้ลองใช้ Executor ร่วมกับการเรียกกลับหรือ RxJava

ขยาย LiveData

LiveData จะถือว่าผู้สังเกตการณ์อยู่ในสถานะ "ใช้งานอยู่" หากวงจรชีวิตของผู้สังเกตการณ์อยู่ในสถานะ STARTED หรือ RESUMED โค้ดตัวอย่างต่อไปนี้แสดงวิธีขยายคลาส 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);
    }
}

การติดตั้งใช้งานเครื่องมือรับฟังราคาในตัวอย่างนี้ประกอบด้วยเมธอดที่สําคัญต่อไปนี้

  • ระบบจะเรียกใช้เมธอด onActive() เมื่อออบเจ็กต์ LiveData มีผู้สังเกตที่ใช้งานอยู่ ซึ่งหมายความว่าคุณต้องเริ่มสังเกตการอัปเดตราคาหุ้นจากวิธีการนี้
  • ระบบจะเรียกใช้เมธอด onInactive() เมื่อออบเจ็กต์ LiveData ไม่มีผู้สังเกตการณ์ที่ทำงานอยู่ เนื่องจากไม่มีผู้สังเกตการณ์ฟังอยู่ จึงไม่มีเหตุผลที่จะเชื่อมต่อกับบริการStockManagerต่อไป
  • เมธอด setValue(T) จะอัปเดตค่าของอินสแตนซ์ LiveData และแจ้งให้ออบเซอร์เวอร์ที่ใช้งานอยู่ทราบเกี่ยวกับการเปลี่ยนแปลง

คุณใช้คลาส StockLiveData ได้ดังนี้

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

วิธีการจะส่ง LifecycleOwner ที่เชื่อมโยงกับมุมมองของข้อมูลโค้ดเป็นอาร์กิวเมนต์แรกobserve() ซึ่งหมายความว่าตัวสังเกตการณ์นี้เชื่อมโยงกับออบเจ็กต์ Lifecycle ที่เชื่อมโยงกับเจ้าของ

  • หากออบเจ็กต์ Lifecycle ไม่ได้อยู่ในสถานะ "ใช้งานอยู่" ระบบจะไม่เรียกใช้ออบเซอร์เวอร์แม้ว่าค่าจะเปลี่ยนแปลงก็ตาม
  • หลังจากทำลายออบเจ็กต์ Lifecycle แล้ว ระบบจะนำเครื่องมือตรวจสอบออกโดยอัตโนมัติ

การที่ออบเจ็กต์ LiveData รับรู้ถึงวงจรของวัตถุหมายความว่าคุณสามารถแชร์ออบเจ็กต์เหล่านั้นระหว่างกิจกรรม ฟragment และบริการหลายรายการได้ หากต้องการให้ตัวอย่างเข้าใจง่าย คุณสามารถติดตั้งใช้งานคลาส LiveData เป็น Singleton ดังนี้

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

และคุณใช้ข้อมูลดังกล่าวในข้อมูลโค้ดต่อไปนี้ได้

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

หลายรายการย่อยและกิจกรรมสามารถสังเกตอินสแตนซ์ MyPriceListener ได้ LiveData จะเชื่อมต่อกับบริการของระบบก็ต่อเมื่อมีบริการอย่างน้อย 1 รายการที่มองเห็นได้และใช้งานอยู่

เปลี่ยนรูปแบบ LiveData

คุณอาจต้องเปลี่ยนแปลงค่าที่จัดเก็บไว้ในออบเจ็กต์ LiveData ก่อนส่งไปยังผู้สังเกตการณ์ หรืออาจต้องแสดงผลอินสแตนซ์ LiveData อื่นโดยอิงตามค่าของอินสแตนซ์อื่น แพ็กเกจ Lifecycle มีคลาส Transformations ที่มีเมธอดตัวช่วยที่รองรับสถานการณ์เหล่านี้

Transformations.map()
ใช้ฟังก์ชันกับค่าที่เก็บไว้ในออบเจ็กต์ LiveData และเผยแพร่ผลลัพธ์ลงไปยังส่วนปลาย

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()
คล้ายกับ map() จะใช้ฟังก์ชันกับค่าที่จัดเก็บไว้ในออบเจ็กต์ LiveData และแยกออกและส่งผลลัพธ์ไป downstream ฟังก์ชันที่ส่งผ่านไปยัง switchMap() จะต้องแสดงผลออบเจ็กต์ LiveData ดังที่แสดงในตัวอย่างต่อไปนี้

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

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

หากคุณคิดว่าจําเป็นต้องใช้ออบเจ็กต์ Lifecycle ภายในออบเจ็กต์ ViewModel การเปลี่ยนรูปแบบอาจเป็นวิธีแก้ปัญหาที่ดีกว่า ตัวอย่างเช่น สมมติว่าคุณมีคอมโพเนนต์ UI ที่ยอมรับที่อยู่และแสดงผลรหัสไปรษณีย์ของที่อยู่นั้น คุณสามารถใช้ ViewModel แบบไม่ซับซ้อนสําหรับคอมโพเนนต์นี้ได้ ดังที่แสดงในโค้ดตัวอย่างต่อไปนี้

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

จากนั้นคอมโพเนนต์ UI จะต้องยกเลิกการลงทะเบียนจากออบเจ็กต์ LiveData ก่อนหน้า และลงทะเบียนกับอินสแตนซ์ใหม่ทุกครั้งที่เรียกใช้ getPostalCode() นอกจากนี้ หากสร้างคอมโพเนนต์ UI ขึ้นมาใหม่ ระบบจะเรียกใช้เมธอด repository.getPostCode() อีกครั้งแทนที่จะใช้ผลลัพธ์ของการเรียกใช้ก่อนหน้านี้

แต่คุณใช้การค้นหารหัสไปรษณีย์เป็นการแปลงอินพุตที่อยู่ได้ ดังที่แสดงในตัวอย่างต่อไปนี้

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

ในกรณีนี้ ระบบจะกําหนดฟิลด์ postalCode เป็นการเปลี่ยนรูปแบบของ addressInput ตราบใดที่แอปของคุณมีผู้สังเกตการณ์ที่ใช้งานอยู่ซึ่งเชื่อมโยงกับช่อง postalCode ระบบจะคํานวณค่าของช่องใหม่และดึงข้อมูลทุกครั้งที่ postalCode มีการเปลี่ยนแปลงaddressInput

กลไกนี้ช่วยให้แอปในระดับที่ต่ำกว่าสร้างออบเจ็กต์ LiveData ที่คำนวณแบบล่าช้าตามคําขอได้ ออบเจ็กต์ ViewModel สามารถรับการอ้างอิงออบเจ็กต์ LiveData ได้อย่างง่ายดาย จากนั้นจึงกำหนดกฎการเปลี่ยนรูปแบบเพิ่มเติม

สร้างการเปลี่ยนรูปแบบใหม่

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

ผสานแหล่งที่มาของ LiveData หลายแหล่ง

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

เช่น หากคุณมีออบเจ็กต์ LiveData ใน UI ที่อัปเดตได้จากฐานข้อมูลในเครื่องหรือเครือข่าย คุณสามารถเพิ่มแหล่งที่มาต่อไปนี้ลงในออบเจ็กต์ MediatorLiveData ได้

  • ออบเจ็กต์ LiveData ที่เชื่อมโยงกับข้อมูลที่จัดเก็บไว้ในฐานข้อมูล
  • ออบเจ็กต์ LiveData ที่เชื่อมโยงกับข้อมูลที่เข้าถึงจากเครือข่าย

กิจกรรมของคุณต้องสังเกตออบเจ็กต์ MediatorLiveData เท่านั้นเพื่อรับการอัปเดตจากทั้ง 2 แหล่ง ดูตัวอย่างโดยละเอียดได้ที่ส่วนภาคผนวก: การเปิดเผยสถานะเครือข่ายในคู่มือเกี่ยวกับสถาปัตยกรรมแอป

แหล่งข้อมูลเพิ่มเติม

หากต้องการดูข้อมูลเพิ่มเติมเกี่ยวกับคลาส LiveData โปรดดูแหล่งข้อมูลต่อไปนี้

ตัวอย่าง

  • Sunflower เป็นแอปสาธิตที่แสดงแนวทางปฏิบัติแนะนำเกี่ยวกับคอมโพเนนต์สถาปัตยกรรม

Codelabs

บล็อก

วิดีโอ