Android源碼解析-LiveData

1 概述

LiveData是一個可被觀察的數據持有類,通常的數據類不一樣,LiveData是生命週期感知的,數據類的生命週期能夠和其餘app組件的生命週期保持一致,例如Activity,fragment和service。這保證了LiveData僅僅會更新處在活動狀態的組件。html

LiveData能夠被當作觀察者模式的實踐,LiveData是一個被觀察的對象,其餘組件會訂閱對它的觀察,當組件處於Started或者Resumed則爲活躍狀態,LiveData只會通知處於這二者狀態的組件更新。同時但願在組件變爲Destroyed狀態時去自動銷燬LiveData和組件的綁定,不至於出現泄漏。java

1.1 優點

  • 確保UI和數據狀態同步android

  • 沒有內存泄漏緩存

  • 不會由於已經中止的Activity致使crash多線程

  • 不須要手動處理生命週期架構

  • 組件時刻保持最新數據併發

  • 支持適當配置更改app

    若是一個Activity或者fragment由於例如設備旋轉而從新建立,它會當即接受到最新可得到的數據。ide

  • 共享資源 多個組件能夠共享同一份數據post

2 實踐

2.1 依賴

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"
複製代碼

2.2 建立LiveData對象

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,暴露了setValuepostValue方法。

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);
    }
}
複製代碼

2.3 監聽LiveData對象

寫一個activity模擬顯示電量變化狀況,一般咱們要在onCreate回調裏開始監聽LiveData,主要出於如下緣由:

  • onCreate是activity建立時的第一個回調,onResume和onStart在activity生命週期內會回調屢次,形成調用監聽屢次造成冗餘。
  • 確保activity和fragment在變成活躍狀態進入started時能夠儘快得到數據更新,因此要儘早開始監聽。

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。

2.4 更新LiveData數據

監聽設置好以後,下面能夠經過修改數據看看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總共有兩個修改數據的方法,他們的區別是什麼呢?

  • setValue是必須在主線程被調用,用來修改LiveData數據。
  • postValue能夠在後臺線程調用,它是向線程的觀察者發送一個task,請求修改數據,可是若是在主線程執行前調用屢次,則只有最後一次會生效。

3 擴展LiveData

上面是使用自帶的MutableLiveData,一樣也能夠本身定義LiveData類。

3.1 自定義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);
	}
}
複製代碼

須要重寫兩個方法:

  • onActive() 當LiveData綁定有活躍狀態的observer時就會調用,在這裏回去註冊廣播得到電池電量變化。
  • onInactive() 當LiveData沒有任何活躍狀態observer綁定時調用,取消註冊廣播。

3.2 得到數據更新

在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());
			}
		});
複製代碼

3.3 共享資源

文章一開始講到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());
			}
		});
複製代碼

4 LiveData轉換

4.1 map

map是將一個LiveData轉換成另外一個LiveData。

Transformations.map(batteryLiveData, new Function<Integer, String>() {
			@Override
			public String apply(Integer input) {
				return input + "%";
			}
		});
複製代碼

4.2 switchMap

第二個參數接收一個方法,經過方法將傳入的第一個參數LiveData轉換成另外一個LiveData。

Transformations.switchMap(sInstance, new Function<Integer, LiveData<? extends String>>() {
			@Override
			public LiveData<? extends String> apply(Integer input) {
				return ...;
			}
		});
複製代碼

5 源碼解析

下面來分析一下LiveData的關鍵源碼。先從LiveData類開始: LiveData裏面主要有幾個上面用到的方法,observe,setValue,postValue,onActive,onInactive等,挨個來分析。

5.1 observe()

@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,FragmentFragmentActivity等都實現了該接口,所以咱們在調用的時候就能夠直接傳入this,它裏面有一個方法能夠得到當前的Lifecycle實例,Lifecycle裏面保存了和生命週期相對應的狀態。

observe方法首先先判斷當前狀態是否是DESTROYED,若是是就能夠徹底忽略,由於已經說過只對處於活躍狀態的組件作更新;接着將owner observer構形成LifecycleBoundObserver實例,這是一個內部類,裏面有關於狀態變換的一系列操做,待會詳細分析;而後將observer和wrapper存入map緩存中,若是observer緩存已存在而且已經和另外一個LifecycleOwner綁定,則拋出異常;若是緩存已經存在則直接忽略;最後調用addObserver方法將LifecycleBoundObserver實例和LifecycleOwner綁定。而addObserver是調用了LifecycleRegistry類的實現。

5.2 ObserverWrapper

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方法。

5.3 setValue postValue

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在主線程修改數據。

6 參考資料

相關文章
相關標籤/搜索