LiveData 為 Android Architecture Component 其中之一,主要用途為持有可觀察數據(observable data),並讓有註冊且為活躍狀態的觀察者自動收到更新。
若了解或實作過 Observer Pattern (觀察者模式)會很容易了解,可以把 LiveData 看作 Subject (主題)也就是資料的來源。對 Subject 有興趣的 observers 可以訂閱主題,訂閱完成後當主題內的數據發生變化時,observers 便會自動收到通知。
基本上 Observer Pattern 是用來取代 polling 的解決方案。關於 Observer Pattern 可以參考這篇
回過頭來,首先看看 LiveData 的 OverView (這裡是官網介紹)
首先 LiveData 是一種擁有可觀察數據的類別(看字面不好懂,直接看實作吧) e.g.,
private MutableLiveData<String> mCurrentName = new MutableLiveData<String>();
因為 LiveData 為 abstract class,通常在實作上會以 MutableLiveData (LiveData’s subclass)取代 LiveData。角括號可以傳入任何型別,包含 Collections,list 等等。
LiveData 最大的特色為它具有生命週期感知(Lifecycle-aware)能力,該能力可以讓 LiveData 得知其他元件(Activity, Fragment, Service)的生命週期。
因此可以避免很多必須手動操作的情況,如螢幕旋轉時需要儲存數據,UI 和數據之間的同步,memoey leak 等等。
通常 LiveData 會和 ViewModel 同時使用。
如何使用 LiveData
1.建立 LiveData 實體並持有特定類型的數據。這通常在 ViewModel 類別內實作
2.建立 Observer 物件並定義 onChanged 方法,該方法內容用來描述當 LiveData 持有的數據改變時所作的事。你通常會在 UI Controlller 內(Activity, fragment)建立 Observer 物件
3.使用 observe 方法連結 Observer 物件和 LiveData 物件。observer 方法需要傳入LifecycleOwner 物件,這讓 Observer 物件訂閱 LiveData 物件並讓 LiveData 可以通知改變。你通常會在 UI Controller 內(activity, fragment)連結 Observer 物件
Note:
你可以藉由 observeForever(Observer) 方法來註冊一個 observer 而不需要結合 LifecycleOwner。在這種情況下 observer 會被當作永遠都是活躍的,因此總是會收到改變的資訊。反之,可以使用 removeObserver(Observer) 來移除 observer
當 LiveData 的資料被更新之後,所有的已註冊且相關連的 LifecycleOwner 為活躍的 observers 會收到通知。
Example
1.Dependency
(參考官網)
2.Create LiveData objects
LiveData 可以包含任何類型的數據,如 List,Map 等等。
LiveData 通常儲存在 ViewModel 內並透過 getter 方法來存取。
public class NameViewModel extends ViewModel { private MutableLiveData<String> mCurrentName = new MutableLiveData<String>(); public MutableLiveData<String> getCurrentName() { return mCurrentName; } }
Note:確保 LiveData 儲存在 ViewModel 而不是 activity 或 fragment
3.Observe LiveData objects
在大多數的情況下,onCreate 方法為初始觀察 LiveData 位置。
在一般的情況下 LiveData 只在數據有更新時且觀察者為活躍的狀態才發送通知。但有 2 個例外,第 1 為當觀察者從非活躍狀態轉為活躍狀態時會收到通知。
第 2 為當觀察者是第 2 次從非活躍狀態轉為活躍狀態,則只有在自上次活動狀態以來該值發生變動時才會收到更新。
(也就是說當觀察者第 1 次從非活躍轉成活躍一定會收到更新。若是第 2 次從非活躍轉成活躍,且必須儲存的數據發生變化才會收到更新)
public class LiveDataMainActivity extends AppCompatActivity { private NameViewModel mViewModel; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.live_data_main_activity); mViewModel = ViewModelProviders.of(this).get(NameViewModel.class); Observer<String> nameObserver = new Observer<String>() { @Override public void onChanged(String newName) { //call back when mViewModel's mCurrentName changed } }; mViewModel.getCurrentName().observe(this, nameObserver); } }
4.Update LiveData objects
LiveData 可以透過 setValue 和 postValue 方法來改變數據,2者的差別為 setValue 可用於main Thread,postValue 可用於 worker thread
String newName = "john doe"; mViewModel.getCurrentName().setValue(newName);
因此當 setValue 呼叫之後,所有已註冊且為活躍的 observer 便會觸發 onChanged 方法
完整 source code
NameViewModel.java
import android.arch.lifecycle.MutableLiveData; import android.arch.lifecycle.ViewModel; public class NameViewModel extends ViewModel { private MutableLiveData<String> mCurrentName = new MutableLiveData<String>(); public MutableLiveData<String> getCurrentName() { return mCurrentName; } }
LiveDataMainActivity.java
import android.arch.lifecycle.Observer; import android.arch.lifecycle.ViewModelProviders; import android.support.v7.app.AppCompatActivity; import android.os.Bundle; import android.view.View; import android.view.View.OnClickListener; import android.widget.Button; import android.widget.TextView; public class LiveDataMainActivity extends AppCompatActivity { private static final String TAG = LiveDataMainActivity.class.getSimpleName(); private NameViewModel mViewModel; private TextView mName; private Button mChangeName; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.live_data_main_activity); mName = (TextView) findViewById(R.id.name); mChangeName = (Button) findViewById(R.id.change); mChangeName.setOnClickListener(new OnClickListener() { @Override public void onClick(View v) { String newName = "john doe"; mViewModel.getCurrentName().setValue(newName); } }); mViewModel = ViewModelProviders.of(this).get(NameViewModel.class); Observer<String> nameObserver = new Observer<String>() { @Override public void onChanged(String newName) { mName.setText(newName); } }; mViewModel.getCurrentName().observe(this, nameObserver); } }
live_data_main_activity.xml
<?xml version="1.0" encoding="utf-8"?> <RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android" xmlns:app="http://schemas.android.com/apk/res-auto" xmlns:tools="http://schemas.android.com/tools" android:layout_width="match_parent" android:layout_height="match_parent" tools:context=".LiveDataMainActivity"> <TextView android:id="@+id/name" android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="Hello World!" app:layout_constraintBottom_toBottomOf="parent" app:layout_constraintLeft_toLeftOf="parent" app:layout_constraintRight_toRightOf="parent" app:layout_constraintTop_toTopOf="parent"/> <Button android:id="@+id/change" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_below="@+id/name" android:text="Change name" /> </RelativeLayout>
Article Comments