介紹
LiveData 是一款基於觀察者模式的可感知生命週期的核心組件。LiveData 爲界面代碼 (Observer)的監視對象
(Observable),當 LiveData 所持有的數據改變時,它會通知相應的界面代碼進行更新。同時,LiveData 持有
界面代碼 Lifecycle 的引用,這意味着它會在界面代碼(LifecycleOwner)的生命週期處於 started 或 resumed
時作出相應更新,而在 LifecycleOwner 被銷燬時停止更新。通過 LiveData,開發者可以方便地構建安全性更高、
性能更好的高響應度用戶界面 .
https://developer.android.google.cn/topic/libraries/architecture/livedata.html
使用必知
推薦在 ViewModel , 而不是在 Activity / Fragment 中保存 LiveData 對象
- 防止 Activity / Fragment 過於臃腫, 這些 UI 控制器只負責顯示數據, 而不負責保存數據.
- 將 LiveData 實例與 Activity / Fragment 實例分離, 使得 LiveData 對象在 Activity / Fragment 實例銷燬時仍能保存數據.
觀察/訂閱 LiveData 對象的最佳時機是 onCreate() 方法中
- 防止因 Activity / Fragment 的 onStart() / onResume() 多次回調, 導致 LiveData 多次被 observe
- 確保 Activity / Fragment 一旦變成活躍狀態,就有可展示的數據
LiveData 使用
一般按照以下步驟:
-
在 ViewModel 類中, 創建 LiveData 的實例, 用來保存指定類型的數據.
/** * 實現每隔一秒鐘,調用 postValue() 設置一次數據 */ // step1 public class TimerViewModel extends ViewModel { private static final String TAG = "TimerViewModel"; private static final int ONE_SECOND = 1000; private MutableLiveData<Long> mutableLiveData = new MutableLiveData<>(); private final Long initTime; public TimerViewModel() { initTime = SystemClock.elapsedRealtime(); new Timer().schedule(new TimerTask() { @Override public void run() { long num = (SystemClock.elapsedRealtime() - initTime) / 1000; // setValue()會拋出異常 : Cannot invoke setValue on a background thread mutableLiveData.postValue(num); } }, ONE_SECOND, ONE_SECOND); } public MutableLiveData<Long> getMutableLiveData() { return mutableLiveData; } /** * 當 Activity 或 Fragment 銷燬時,會回調該方法 */ @Override protected void onCleared() { super.onCleared(); Log.e(TAG, "onCleared: "); } }
-
在 Activity / Fragment 創建 Observer 對象, 實現 onChanged() 方法, 當 LiveData 對象中保存的數據發生改變時會回調 onChanged() 方法, 我們可以在該方法中進行更新 UI 操作.
// step2 Observer<Long> observer = new Observer<Long>() { @Override public void onChanged(@Nullable Long aLong) { textView.setText(String.valueOf(aLong)); } };
-
使用 LiveData 對象的 observe(LifecycleOwner owner, Observer observer) 方法, 將 Observer 對象訂閱到 LiveData 對象上; 也可以使用 observeForever(Observer oberver) 方法不傳 LifecycleOwner 參數訂閱 Observer, 這時 Observer 被認爲始終處於活動狀態.
public class LiveDataActivity extends AppCompatActivity { @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_live_data); textView = findViewById(R.id.tv_title); // step2 Observer<Long> observer = new Observer<Long>() { @Override public void onChanged(@Nullable Long aLong) { textView.setText(String.valueOf(aLong)); } }; // step3 timerViewModel = ViewModelProviders.of(this).get(TimerViewModel.class); timerViewModel.getMutableLiveData().observe(this, observer); } }
LiveData 更新數據
MutableLiveData 類提供了兩個公開方法: setValue(T) 和 postValue(T) , 如果需要更新 LiveData 對象存儲的數據, 必須需要使用這兩個方法.
public void click(View view) {
timerViewModel.getMutableLiveData().postValue(100L);
}
setValue(T) 和 postValue(T) 區別 :
setValue(T) 必須在主線程中調用 , 而 postValue(T) 既可以在主線程中調用, 也可以在子線程中調用 .
LiveData 擴展
需求: 在 Activity 處於前臺 started 時 , 子線程開始計數, 並更新顯示到 UI 上, 在 Activity 處於後臺 paused 時, 暫停計數, 再次回到前臺時,繼續計數.
-
繼承擴展 MutableLiveData ,覆蓋 onActive() 和 onInactive() 方法, 根據標識是否 postValue 更新數據.
public class CountLiveData extends MutableLiveData<Integer> { private static final String TAG = "CountLiveData"; private int count; private boolean isRun = true; private final CountTask countTask; public CountLiveData() { countTask = new CountTask(); countTask.start(); } @Override protected void onActive() { super.onActive(); Log.e(TAG, "onActive: "); countTask.interrupt(); isRun = true; } @Override protected void onInactive() { super.onInactive(); Log.e(TAG, "onInactive: "); isRun = false; } private class CountTask extends Thread { @Override public void run() { super.run(); while (true) { if (!isRun) { try { Thread.sleep(Integer.MAX_VALUE); } catch (InterruptedException e) { e.printStackTrace(); } } count++; postValue(count); try { Thread.sleep(1000); } catch (InterruptedException e) { e.printStackTrace(); } } } } }
-
創建 ViewModel , 存儲 LiveData 對象中的數據.
public class CountViewModel extends ViewModel { private static final String TAG = "CountViewModel"; CountLiveData countLiveData; public CountViewModel() { countLiveData = new CountLiveData(); } public CountLiveData getCountLiveData() { return countLiveData; } /** * Activity / Fragment 銷燬時回調該方法 */ @Override protected void onCleared() { super.onCleared(); Log.e(TAG, "onCleared: "); } }
-
Activity 中創建 Observer , 訂閱監聽 LiveData 中的數據變化 , 並更新 UI
public class LiveDataActivity extends AppCompatActivity { @Override protected void onCreate(Bundle savedInstanceState) { // 計數 CountViewModel countViewModel = ViewModelProviders.of(this).get(CountViewModel.class); Observer<Integer> countObserver = new Observer<Integer>() { @Override public void onChanged(@Nullable Integer integer) { countTextView.setText("計數: " + String.valueOf(integer)); } }; countViewModel.getCountLiveData().observe(this, countObserver); } @Override protected void onStart() { super.onStart(); Log.e("CountLiveData", "LiveDataActivity -> onStart(): " ); } @Override protected void onResume() { super.onResume(); Log.e("CountLiveData", "LiveDataActivity -> onResume(): " ); } @Override protected void onRestart() { super.onRestart(); Log.e("CountLiveData", "LiveDataActivity -> onRestart(): " ); } @Override protected void onPause() { super.onPause(); Log.e("CountLiveData", "LiveDataActivity -> onPause(): " ); } public void click(View view) { startActivity(new Intent(this, LiveDataSecondActivity.class)); timerViewModel.getMutableLiveData().postValue(100L); } }
效果圖
由 GIF 圖可知: Activity 活躍時, 子線程每隔一秒鐘 postValue() 一次數據給 observer, 當 Activity 變成不活躍時, 子線程暫停了 postValue() , 再次回到活躍狀態時, 接着計數開始 postValue.