LiveData是一個可被觀察的數據持有類,通常的數據類不一樣,LiveData是生命週期感知的,數據類的生命週期能夠和其餘app組件的生命週期保持一致,例如Activity,fragment和service。這保證了LiveData僅僅會更新處在活動狀態的組件。html
LiveData能夠被當作觀察者模式的實踐,LiveData是一個被觀察的對象,其餘組件會訂閱對它的觀察,當組件處於Started
或者Resumed
則爲活躍狀態,LiveData只會通知處於這二者狀態的組件更新。同時但願在組件變爲Destroyed
狀態時去自動銷燬LiveData和組件的綁定,不至於出現泄漏。java
確保UI和數據狀態同步android
沒有內存泄漏緩存
不會由於已經中止的Activity致使crash多線程
不須要手動處理生命週期架構
組件時刻保持最新數據併發
支持適當配置更改app
若是一個Activity或者fragment由於例如設備旋轉而從新建立,它會當即接受到最新可得到的數據。ide
共享資源 多個組件能夠共享同一份數據post
LiveData是Android官方架構Jetpack的組成部分,架構組件所有在google的Maven倉庫裏,想要使用能夠在項目的build.gradle文件裏添加google()
依賴。
allprojects {
repositories {
google() //引入livedata
jcenter()
}
}
複製代碼
在模塊的build.gradle文件中加入lifecycle:extensions依賴
implementation "android.arch.lifecycle:extensions:1.1.1"
複製代碼
LiveData一般和Jetpack架構下的另外一個組件ViewModel
配合使用,ViewModel是一個負責爲Activity或者Fragment準備和管理數據的類,同時處理和應用剩餘部分的通訊,注意ViewModel僅僅負責管理UI上的數據,其餘都無權干涉,它和組件生命週期綁定,只有Activity結束了,它纔會被銷燬。
咱們建立一個提供電池電量信息的ViewModel:
public class BatteryViewModel extends ViewModel {
private MutableLiveData<Integer> currentBattery;
public MutableLiveData<Integer> getCurrentBatteryData() {
if (currentBattery == null) {
currentBattery = new MutableLiveData<>();
}
return currentBattery;
}
}
複製代碼
這裏使用了MutableLiveData
類來保存電量數據,它繼承了LiveData,暴露了setValue
、postValue
方法。
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);
}
}
複製代碼
寫一個activity模擬顯示電量變化狀況,一般咱們要在onCreate回調裏開始監聽LiveData,主要出於如下緣由:
LiveData在用非活躍狀態進入活躍狀態時一樣能夠接受到更新,可是若是第二次從非活躍狀態進入活躍狀態,那麼只有當上一次變成活躍態的數據發生變化時纔會接受更新。
public class BatteryActivity extends AppCompatActivity {
private int battery = 100;
private BatteryViewModel mBatteryViewModel;
@Override
protected void onCreate(@Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_livedata_battery);
//在當前activity範圍內建立或者得到viewmodel實例
mBatteryViewModel = ViewModelProviders.of(this).get(BatteryViewModel.class);
final TextView tvBattery = findViewById(R.id.tv_battery);
//設置觀察者
Observer<Integer> batteryOb = new Observer<Integer>() {
@Override
public void onChanged(@Nullable Integer integer) {
tvBattery.setText(String.format("電量:^[0-9]*$", integer));
}
};
//將數據綁定到觀察者
mBatteryViewModel.getCurrentBatteryData().observe(this, batteryOb);
}
}
複製代碼
ViewModelProviders
是lifecycle:extensions模塊下的類,首先經過of(this)
建立一個ViewModelProvider實例,再經過get方法去得到(若是有)或者建立一個viewmodel,而後建立一個Observer
,將它和viewmodel綁定,監聽數據的變化,在onChanged
回調內實時修改UI。
監聽設置好以後,下面能夠經過修改數據看看ui是否被實時修改,點擊開始統計按鈕,讓電量減一來模擬掉電狀況。
LiveData更改數據的方法不是public類型的,只在內部本身調用,全部這裏纔會使用MutableLiveData,他暴露了修改數據的公共方法。這裏修改電量減一就是用到了setValue方法。
findViewById(R.id.btn_start).setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
mBatteryViewModel.getCurrentBatteryData().postValue(battery--);
}
});
複製代碼
能夠看到MutableLiveData
總共有兩個修改數據的方法,他們的區別是什麼呢?
上面是使用自帶的MutableLiveData,一樣也能夠本身定義LiveData類。
自定義一個BatteryLiveData類繼承自LiveData,經過廣播去接受系統電池電量,經過setValue將數據設置給LiveData。
public class BatteryLiveData extends LiveData<Integer> {
private Context context;
private BroadcastReceiver receiver = new BroadcastReceiver() {
@Override
public void onReceive(Context context, Intent intent) {
setValue(intent.getIntExtra("level", 0));
}
};
public BatteryLiveData(Context context) {
this.context = context;
}
@Override
protected void onActive() {
super.onActive();
IntentFilter filter = new IntentFilter();
filter.addAction(Intent.ACTION_BATTERY_CHANGED);
context.registerReceiver(receiver, filter);
}
@Override
protected void onInactive() {
super.onInactive();
context.unregisterReceiver(receiver);
}
}
複製代碼
須要重寫兩個方法:
在activity裏構造LiveData實例,同時調用observe()
方法將activity和LiveData綁定。
BatteryLiveData batteryLiveData = new BatteryLiveData(this);
batteryLiveData.observe(this, new Observer<Integer>() {
@Override
public void onChanged(@Nullable Integer integer) {
tvBattery.setText(integer.toString());
}
});
複製代碼
文章一開始講到LiveData的優點之一就是共享資源,能夠將LiveData設計成單例模式,在任何須要的地方調用observe()綁定監聽。
public class BatteryLiveData extends LiveData<Integer> {
...
@MainThread
public static BatteryLiveData getInstance(Context context) {
if (sInstance == null) {
sInstance = new BatteryLiveData(context);
}
return sInstance;
}
private BatteryLiveData(Context context) {
this.context = context;
}
...
}
BatteryLiveData.getInstance(this).observe(this, new Observer<Integer>() {
@Override
public void onChanged(@Nullable Integer integer) {
tvBattery.setText(integer.toString());
}
});
複製代碼
map是將一個LiveData轉換成另外一個LiveData。
Transformations.map(batteryLiveData, new Function<Integer, String>() {
@Override
public String apply(Integer input) {
return input + "%";
}
});
複製代碼
第二個參數接收一個方法,經過方法將傳入的第一個參數LiveData轉換成另外一個LiveData。
Transformations.switchMap(sInstance, new Function<Integer, LiveData<? extends String>>() {
@Override
public LiveData<? extends String> apply(Integer input) {
return ...;
}
});
複製代碼
下面來分析一下LiveData的關鍵源碼。先從LiveData類開始: LiveData裏面主要有幾個上面用到的方法,observe
,setValue
,postValue
,onActive
,onInactive
等,挨個來分析。
@MainThread
public void observe(@NonNull LifecycleOwner owner, @NonNull Observer<T> observer) {
if (owner.getLifecycle().getCurrentState() == DESTROYED) {
// ignore
return;
}
LifecycleBoundObserver wrapper = new LifecycleBoundObserver(owner, observer);
ObserverWrapper existing = mObservers.putIfAbsent(observer, wrapper);
if (existing != null && !existing.isAttachedTo(owner)) {
throw new IllegalArgumentException("Cannot add the same observer"
+ " with different lifecycles");
}
if (existing != null) {
return;
}
owner.getLifecycle().addObserver(wrapper);
}
public interface LifecycleOwner {
@NonNull
Lifecycle getLifecycle();
}
複製代碼
observe有兩個參數,第一個是LifecycleOwner
,Fragment和FragmentActivity等都實現了該接口,所以咱們在調用的時候就能夠直接傳入this,它裏面有一個方法能夠得到當前的Lifecycle實例,Lifecycle
裏面保存了和生命週期相對應的狀態。
observe方法首先先判斷當前狀態是否是DESTROYED
,若是是就能夠徹底忽略,由於已經說過只對處於活躍狀態的組件作更新;接着將owner observer構形成LifecycleBoundObserver
實例,這是一個內部類,裏面有關於狀態變換的一系列操做,待會詳細分析;而後將observer和wrapper存入map緩存中,若是observer緩存已存在而且已經和另外一個LifecycleOwner
綁定,則拋出異常;若是緩存已經存在則直接忽略;最後調用addObserver方法將LifecycleBoundObserver
實例和LifecycleOwner
綁定。而addObserver是調用了LifecycleRegistry
類的實現。
private abstract class ObserverWrapper {
final Observer<T> mObserver;
boolean mActive;
int mLastVersion = START_VERSION;
ObserverWrapper(Observer<T> observer) {
mObserver = observer;
}
abstract boolean shouldBeActive();
boolean isAttachedTo(LifecycleOwner owner) {
return false;
}
void detachObserver() {
}
void activeStateChanged(boolean newActive) {
if (newActive == mActive) {
return;
}
// immediately set active state, so we'd never dispatch anything to inactive
// owner
mActive = newActive;
boolean wasInactive = LiveData.this.mActiveCount == 0;
LiveData.this.mActiveCount += mActive ? 1 : -1;
//過去是inactive,如今是active
if (wasInactive && mActive) {
onActive();
}
//過去沒有訂閱,而且如今是inactive
if (LiveData.this.mActiveCount == 0 && !mActive) {
onInactive();
}
//如今是active
if (mActive) {
dispatchingValue(this);
}
}
}
class LifecycleBoundObserver extends ObserverWrapper implements GenericLifecycleObserver {
...
@Override
public void onStateChanged(LifecycleOwner source, Lifecycle.Event event) {
if (mOwner.getLifecycle().getCurrentState() == DESTROYED) {
removeObserver(mObserver);
return;
}
activeStateChanged(shouldBeActive());
}
}
複製代碼
ObserverWrapper裏面封裝了關於狀態的操做,包括判斷是否處於活躍狀態、observer是否綁定到lifecycleowner以及更改activity狀態等。
activeStateChanged首先判斷新來的狀態和舊狀態是否相同,相同則忽略,而後判斷LiveData上的活躍態的數量是否爲0,爲0說明以前處於Inactive,而後統計如今的訂閱數,接着就是三個if判斷,註釋在代碼裏。正式這三個判斷,LiveData能夠接收到onActive和onInactive的回調。
dispatchingValue(this)是當狀態變爲active時調用,用來更新數據。裏面會用到considerNotify方法。
private final Runnable mPostValueRunnable = new Runnable() {
@Override
public void run() {
Object newValue;
synchronized (mDataLock) {
newValue = mPendingData;
mPendingData = NOT_SET;
}
//noinspection unchecked
setValue((T) newValue);
}
};
protected void postValue(T value) {
boolean postTask;
synchronized (mDataLock) {
postTask = mPendingData == NOT_SET;
mPendingData = value;
}
if (!postTask) {
return;
}
ArchTaskExecutor.getInstance().postToMainThread(mPostValueRunnable);
}
@MainThread
protected void setValue(T value) {
assertMainThread("setValue");
mVersion++;
mData = value;
dispatchingValue(null);
}
private void considerNotify(ObserverWrapper observer) {
if (!observer.mActive) {
return;
}
if (!observer.shouldBeActive()) {
observer.activeStateChanged(false);
return;
}
if (observer.mLastVersion >= mVersion) {
return;
}
observer.mLastVersion = mVersion;
//noinspection unchecked
observer.mObserver.onChanged((T) mData);
}
複製代碼
setValue會調用dispatchingValue方法,接着調用considerNotify,在最後調用onChange()回調,就能收到數據變化。
postValue以前說過是往主線程發送事件,同時加鎖保持佔用,防止多線程併發競爭致使的數據錯誤,由於每次postValue成功都會對mPendingData重置爲NOT_SET。而後想主線程發送Runnable對象,Runnable實例的run方法會執行setValue在主線程修改數據。