JetPack之LiveData與ViewModel

JetPack之LiveData與ViewModel

1.簡述

LiveData從字面上看是與生命周期相關(guān)的數(shù)據(jù),是一個數(shù)據(jù)的持有者揍移。谷歌官方說明是“LiveData 具有生命周期感知能力,如果觀察者(由 Observer 類表示)的生命周期處于 STARTED 或 RESUMED 狀態(tài),則 LiveData 會認(rèn)為該觀察者處于活躍狀態(tài)黍图。LiveData 只會將更新通知給活躍的觀察者。為觀察 LiveData 對象而注冊的非活躍觀察者不會收到更改通知奴烙≈唬”

2.使用

LiveData是一個抽象類,內(nèi)部沒有暴露任何公共方法切诀,它的最簡單的實現(xiàn)者是MutableLiveData揩环。使用時,通過setValue或postValue來發(fā)送數(shù)據(jù)內(nèi)容幅虑,后者可以在子線程中調(diào)用丰滑。簡單使用示例:

public class LiveDataActivity extends AppCompatActivity {
    private static final String TAG = "LiveDataActivity";

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_second);

        MutableLiveData<String> liveData = new MutableLiveData<>();
        liveData.observe(this, new Observer<String>() {
            @Override
            public void onChanged(String s) {
                Log.e(TAG, "new data: " + s);
            }
        });
        liveData.setValue("hello world");
    }
}

輸出為:

E/LiveDataActivity: new data: hello world

上面是LiveData的最簡單的使用。事實上倒庵,Jetpack并不建議這樣使用LiveData褒墨,請確保將用于更新界面的 LiveData 對象存儲在 ViewModel 對象中,而不是將其存儲在 Activity 或 Fragment 中擎宝,原因如下:

1)避免 Activity 和 Fragment 過于龐大∮袈瑁現(xiàn)在,這些界面控制器負(fù)責(zé)顯示數(shù)據(jù)认臊,但不負(fù)責(zé)存儲數(shù)據(jù)狀態(tài)圃庭。

2)將 LiveData 實例與特定的 Activity 或 Fragment 實例分離開,并使對象在配置更改后繼續(xù)存在失晴。

也就是說剧腻,LiveData一般在ViewModel中創(chuàng)建,以減少Activity中邏輯涂屁,同時避免Activity因為橫豎屏切換導(dǎo)致的數(shù)據(jù)丟失书在。
我們將上述示例代碼修改一下,使用LiveData來完成拆又。先在項目的gradle中添加依賴(因為不同的版本中儒旬,ViewModel獲取方式有點不同):

def lifecycle_version = "2.2.0"
// ViewModel
implementation "androidx.lifecycle:lifecycle-viewmodel:$lifecycle_version"
// LiveData
implementation "androidx.lifecycle:lifecycle-livedata:$lifecycle_version"

創(chuàng)建SimpleViewModel.java:

public class SimpleViewModel extends ViewModel {

    private final MutableLiveData<String> mLiveData;
    private static int mCurTime = 0;

    public SimpleViewModel() {
        mLiveData = new MutableLiveData<>();
        mCurTime ++;
        mLiveData.postValue("number " + mCurTime + ", viewModel hashcode: " + hashCode());//1
    }

    public LiveData<String> getDataNotify(){
        return mLiveData;
    }
}

最后Activity中代碼變成如下:

public class LiveDataActivity extends AppCompatActivity {
    private static final String TAG = "LiveDataActivity";

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_second);

        SimpleViewModel simpleViewModel = new ViewModelProvider(this)
                    .get(SimpleViewModel.class);
        simpleViewModel.getDataNotify().observe(this, new Observer<String>() {
            @Override
            public void onChanged(String s) {
                Log.e(TAG, "new data: " + s);
            }
        });
    }
}

ViewModel不能使用new來創(chuàng)建,而應(yīng)該通過ViewModelProvider來創(chuàng)建帖族,原因是如果我們通過new的方式創(chuàng)建栈源,和我們不使用ViewModel+Lifecycle+LiveData的方式?jīng)]什么區(qū)別,而通過ViewModelProvider竖般,內(nèi)部會協(xié)助管理ViewModel的生命周期甚垦。
我們嘗試橫豎屏切換,按照代碼邏輯,如果LiveData重建了艰亮,那么內(nèi)部的mCurTime靜態(tài)成員應(yīng)該每次都會自增1闭翩。實際日志輸出如下:

2020-06-14 18:00:46.448 4506-4506/com.hudson.newfeaturetest E/LiveDataActivity: new data: number 1, viewModel hashcode: 202833815
2020-06-14 18:00:53.435 4506-4506/com.hudson.newfeaturetest E/LiveDataActivity: new data: number 1, viewModel hashcode: 202833815

可以發(fā)現(xiàn)兩次結(jié)果一模一樣,而且即便LiveData在ViewModel構(gòu)建時的注釋1處已經(jīng)postValue發(fā)送了數(shù)據(jù)迄埃,橫豎屏切換之后疗韵,Activity中仍然能夠獲取到之前的內(nèi)容,也就是說ViewModel似乎幫我們把數(shù)據(jù)存儲起來了侄非。這就跟ViewModel的生命周期相關(guān)了蕉汪。

3 ViewModel的生命周期

ViewModel 對象存在的時間范圍是從獲取 ViewModel 時傳遞給 ViewModelProvider 的 Lifecycle開始,ViewModel 將一直留在內(nèi)存中彩库,直到限定其存在時間范圍的 Lifecycle 永久消失:對于 Activity肤无,是在 Activity 完成時;而對于 Fragment骇钦,是在 Fragment 分離時宛渐。如下圖說明了 Activity 經(jīng)歷屏幕旋轉(zhuǎn)而后結(jié)束的過程中所處的各種生命周期狀態(tài),F(xiàn)ragment也是類似的眯搭。


ViewModel的生命周期.png

通常在系統(tǒng)首次調(diào)用 Activity 對象的 onCreate() 方法時請求 ViewModel窥翩。系統(tǒng)可能會在 Activity 的整個生命周期內(nèi)多次調(diào)用 onCreate(),如在旋轉(zhuǎn)設(shè)備屏幕時鳞仙、內(nèi)存不足回收Activity后的重建時寇蚊。ViewModel 存在的時間范圍是從您首次請求 ViewModel 直到 Activity 完成并銷毀。
由于這個特性棍好,ViewModel可以用于同一個Activity內(nèi)部的多個Fragment之間來進(jìn)行數(shù)據(jù)共享仗岸。

public class SharedViewModel extends ViewModel {
    private final MutableLiveData<Item> selected = new MutableLiveData<Item>();

    public void select(Item item) {
        selected.setValue(item);
    }

    public LiveData<Item> getSelected() {
        return selected;
    }
}

public class MasterFragment extends Fragment {
    private SharedViewModel model;

    public void onViewCreated(@NonNull View view, Bundle savedInstanceState) {
        super.onViewCreated(view, savedInstanceState);
        model = new ViewModelProvider(requireActivity()).get(SharedViewModel.class);
        itemSelector.setOnClickListener(item -> {
            model.select(item);
        });
    }
}

public class DetailFragment extends Fragment {

    public void onViewCreated(@NonNull View view, Bundle savedInstanceState) {
        super.onViewCreated(view, savedInstanceState);
        SharedViewModel model = new ViewModelProvider(requireActivity()).get(SharedViewModel.class);
        model.getSelected().observe(getViewLifecycleOwner(), { item ->
           // Update the UI.
        });
    }
}

這兩個 Fragment 可以使用其 Activity 范圍共享 ViewModel 來處理此類通信。

需要注意的是借笙,ViewModel存儲數(shù)據(jù)的特性并不是指持久性數(shù)據(jù)扒怖,而是指在它所處的LifecycleOwner的生命周期范圍內(nèi)的全局存儲,只要我們能拿到這個LifecycleOwner业稼,我們便可以拿到之前它創(chuàng)建的那個ViewModel盗痒。如果一個Activity通過返回鍵點擊被銷毀了,destroyed低散,那么ViewModel也將會執(zhí)行onCleared方法來清理數(shù)據(jù)俯邓,這時候你重新打開該Activity,這時會新建一個ViewModel熔号,而不是使用之前的ViewModel稽鞭,因為舊Activity已經(jīng)和原來的ViewModel解綁了递鹉。我們可以繼續(xù)使用上面的示例绩鸣,先按下back返回鍵回到主頁职烧,再重新進(jìn)入与纽,對比兩次的日志:

2020-06-14 18:40:05.918 5386-5386/com.hudson.newfeaturetest E/LiveDataActivity: new data: number 1, viewModel hashcode: 118099635

2020-06-14 18:40:36.477 5386-5386/com.hudson.newfeaturetest E/LiveDataActivity: new data: number 2, viewModel hashcode: 20262912

可以看到內(nèi)部的靜態(tài)成員自增了切端。

4.ViewModel源碼跟蹤

4.1 ViewModel的創(chuàng)建過程

從前面代碼中的ViewModelProvider開始币叹,我們可以找到ViewModel的創(chuàng)建過程
ViewModelProvider.java

...
public ViewModelProvider(@NonNull ViewModelStoreOwner owner) {
    this(owner.getViewModelStore(), owner instanceof HasDefaultViewModelProviderFactory
            ? ((HasDefaultViewModelProviderFactory) owner).getDefaultViewModelProviderFactory()
            : NewInstanceFactory.getInstance());
}

 public ViewModelProvider(@NonNull ViewModelStore store, @NonNull Factory factory) {
    mFactory = factory;
    mViewModelStore = store;
}

...

內(nèi)部通過this()方式調(diào)用了自身的構(gòu)造方法赏壹,并傳入兩個參數(shù)百拓,一個是ViewModelStore亮瓷,另一個是Factory琴拧。
ViewModelStore從字面意思上看,它應(yīng)該是我們ViewModel的存儲器嘱支,因為Activity本身可以有多個ViewModel蚓胸,因此可以猜測內(nèi)部維護了一個ViewModel列表。在我們調(diào)用的構(gòu)造方法中除师,ViewModelStore是通過ViewModelStoreOwner來獲取的沛膳,而我們傳入的ViewModelStoreOwner實際上是Activity。果然汛聚,在我們的ComponentActivity中锹安,實現(xiàn)了ViewModelStoreOwner接口,如下所示:

public class ComponentActivity extends androidx.core.app.ComponentActivity implements
    LifecycleOwner,
    ViewModelStoreOwner,
    SavedStateRegistryOwner,
    OnBackPressedDispatcherOwner {
...
    public ComponentActivity() {
        Lifecycle lifecycle = getLifecycle();
        //noinspection ConstantConditions
        if (lifecycle == null) {
            throw new IllegalStateException("getLifecycle() returned null in ComponentActivity's "
                    + "constructor. Please make sure you are lazily constructing your Lifecycle "
                    + "in the first call to getLifecycle() rather than relying on field "
                    + "initialization.");
        }
        // ...
        getLifecycle().addObserver(new LifecycleEventObserver() {
            @Override
            public void onStateChanged(@NonNull LifecycleOwner source,
                    @NonNull Lifecycle.Event event) {
                if (event == Lifecycle.Event.ON_DESTROY) {
                    if (!isChangingConfigurations()) {
                        getViewModelStore().clear();//1
                    }
                }
            }
        });

        if (19 <= SDK_INT && SDK_INT <= 23) {
            getLifecycle().addObserver(new ImmLeaksCleaner(this));
        }
    }

    @NonNull
    @Override
    public ViewModelStore getViewModelStore() {//2
        if (getApplication() == null) {
            throw new IllegalStateException("Your activity is not yet attached to the "
                    + "Application instance. You can't request ViewModel before onCreate call.");
        }
        if (mViewModelStore == null) {
            NonConfigurationInstances nc =
                    (NonConfigurationInstances) getLastNonConfigurationInstance();//3
            if (nc != null) {
                // Restore the ViewModelStore from NonConfigurationInstances
                mViewModelStore = nc.viewModelStore;
            }
            if (mViewModelStore == null) {
                mViewModelStore = new ViewModelStore();
            }
        }
        return mViewModelStore;
    }
...
}

內(nèi)部在注釋2處的方法中判斷ViewModelStore是否為空倚舀,為空則創(chuàng)建新對象叹哭。注釋3處的NonConfigurationInstances是Activity能在橫豎屏切換時保持生命周期而不銷毀的,從字面上看意思是與配置無關(guān)的實例痕貌。我們看下這個getLastNonConfigurationInstance方法:

/**
 * Retrieve the non-configuration instance data that was previously
 * returned by {@link #onRetainNonConfigurationInstance()}.  This will
 * be available from the initial {@link #onCreate} and
 * {@link #onStart} calls to the new instance, allowing you to extract
 * any useful dynamic state from the previous instance.
 *
 * <p>Note that the data you retrieve here should <em>only</em> be used
 * as an optimization for handling configuration changes.  You should always
 * be able to handle getting a null pointer back, and an activity must
 * still be able to restore itself to its previous state (through the
 * normal {@link #onSaveInstanceState(Bundle)} mechanism) even if this
 * function returns null.
 *
 * <p><strong>Note:</strong> For most cases you should use the {@link Fragment} API
 * {@link Fragment#setRetainInstance(boolean)} instead; this is also
 * available on older platforms through the Android support libraries.
 *
 * @return the object previously returned by {@link #onRetainNonConfigurationInstance()}
 */
@Nullable
public Object getLastNonConfigurationInstance() {
    return mLastNonConfigurationInstances != null
            ? mLastNonConfigurationInstances.activity : null;
}

與之對應(yīng)的還有一個onRetainNonConfigurationInstance()方法风罩,這兩個方法與onSaveInstanceState()和onRestoreInstanceState()方法類似,這兩個方法可以直接使用Object來保存Activity銷毀與重建的信息舵稠。從上面的getLastNonConfigurationInstance()注釋中我們看到超升,大部分情況下,我們可以使用Fragment的setRetainInstance來設(shè)置Fragment是否跟隨Activity重建而重建哺徊。

另外在注釋1處通過getLifecycle().addObserver()來給Activity的生命周期添加了一個監(jiān)聽器室琢,并在內(nèi)部判斷Lifecycle的事件為ON_DESTROY事件且不是由于配置信息變更引起時,調(diào)用了ViewModelStore的clear方法唉工,我們跟蹤到內(nèi)部研乒,如下
ViewModelStore.java

public class ViewModelStore {
    private final HashMap<String, ViewModel> mMap = new HashMap<>();

    final void put(String key, ViewModel viewModel) {
        ViewModel oldViewModel = mMap.put(key, viewModel);
        if (oldViewModel != null) {
            oldViewModel.onCleared();
        }
    }

    final ViewModel get(String key) {
        return mMap.get(key);
    }

    public final void clear() {
        for (ViewModel vm : mMap.values()) {
            vm.clear();
        }
        mMap.clear();
    }
}

可以看到上面ViewModelStore中確實維護了一個String為key,ViewModel為value的HashMap淋硝,并在clear方法中遍歷map雹熬,依次調(diào)用了ViewModel的clear()方法

ViewModel.java

...
@MainThread
final void clear() {
    mCleared = true;
    // Since clear() is final, this method is still called on mock objects
    // and in those cases, mBagOfTags is null. It'll always be empty though
    // because setTagIfAbsent and getTag are not final so we can skip
    // clearing it
    if (mBagOfTags != null) {
        synchronized (mBagOfTags) {
            for (Object value : mBagOfTags.values()) {
                // see comment for the similar call in setTagIfAbsent
                closeWithRuntimeException(value);//2
            }
        }
    }
    onCleared();//1
}
...

在注釋1處調(diào)用了我們之前ViewModel生命周期中的onCleared方法。因此驗證了之前生命周期中所說的谣膳,如果Activity進(jìn)入的Finished態(tài)的話竿报,ViewModel生命周期也結(jié)束了。其實clear()方法中我們發(fā)現(xiàn)继谚,ViewModel生命周期的結(jié)束烈菌,僅僅是把mCleared的標(biāo)識位設(shè)置成了true,同時注釋2處會調(diào)用Closeable對象的close方法,然后再調(diào)用了1處的onCleared()抽象方法芽世。因此如果我們在ViewModel中執(zhí)行一些異步耗時操作挚赊,內(nèi)部邏輯依然會繼續(xù)執(zhí)行,直到全部完成济瓢,因此在ViewModel中荠割,我們也應(yīng)該注意這類問題,只不過這部分的內(nèi)存泄漏并不會影響到Activity旺矾,因為ViewModelStore已經(jīng)把它從Map中移除了蔑鹦。

回到之前的ViewModelProvider構(gòu)造方法中,第二個參數(shù)是一個Factory箕宙,它的定義如下
ViewModelProvider.java

...
 /**
 * Implementations of {@code Factory} interface are responsible to instantiate ViewModels.
 */
public interface Factory {
    /**
     * Creates a new instance of the given {@code Class}.
     * <p>
     *
     * @param modelClass a {@code Class} whose instance is requested
     * @param <T>        The type parameter for the ViewModel.
     * @return a newly created ViewModel
     */
    @NonNull
    <T extends ViewModel> T create(@NonNull Class<T> modelClass);
}

@NonNull
@MainThread
public <T extends ViewModel> T get(@NonNull Class<T> modelClass) {
    String canonicalName = modelClass.getCanonicalName();//1
    if (canonicalName == null) {
        throw new IllegalArgumentException("Local and anonymous classes can not be ViewModels");
    }
    return get(DEFAULT_KEY + ":" + canonicalName, modelClass);//2
}

@NonNull
@MainThread
public <T extends ViewModel> T get(@NonNull String key, @NonNull Class<T> modelClass) {
    ViewModel viewModel = mViewModelStore.get(key);//3

    if (modelClass.isInstance(viewModel)) {
        if (mFactory instanceof OnRequeryFactory) {
            ((OnRequeryFactory) mFactory).onRequery(viewModel);
        }
        return (T) viewModel;
    } else {
        //noinspection StatementWithEmptyBody
        if (viewModel != null) {
            // TODO: log a warning.
        }
    }
    if (mFactory instanceof KeyedFactory) {
        viewModel = ((KeyedFactory) (mFactory)).create(key, modelClass);//4
    } else {
        viewModel = (mFactory).create(modelClass);//5
    }
    mViewModelStore.put(key, viewModel);//6
    return (T) viewModel;
}
...

可以看出嚎朽,這是一個ViewModel的構(gòu)建工廠,也就是說柬帕,我們外界可以提供一個用于構(gòu)建我們自定義ViewModel的構(gòu)建工廠哟忍,然后ViewModelProvider會通過它來構(gòu)建我們的實例。由于我們沒有傳入構(gòu)建工廠雕崩,因此ViewModelProvider會為我們創(chuàng)建默認(rèn)的構(gòu)建工廠(在部分版本中必須傳入構(gòu)建工廠)魁索。
ViewModelProvider的構(gòu)建完成了,我們接著看get方法盼铁,注釋1處獲取到了class的名字粗蔚,并在注釋2處和DEFAULT_KEY拼接起來,DEFAULT_KEY是"androidx.lifecycle.ViewModelProvider.DefaultKey"饶火,因此最終拼接起來是"androidx.lifecycle.ViewModelProvider.DefaultKey" + 名字鹏控。最終先在注釋3處獲取HashMap中是否已經(jīng)存儲了該值,有就直接獲取肤寝,沒有則通過注釋4或5處利用之前的構(gòu)建工廠創(chuàng)建当辐,然后在6處緩存起來,之后返回鲤看。至此缘揪,ViewModel分析完畢。

4.2 LiveData的數(shù)據(jù)觀察者注冊過程

前面分析中义桂,ViewModelStore內(nèi)部維護了一個String-ViewModel的HashMap集合找筝,并會在Activity銷毀時進(jìn)行一些清理工作,也知道了為什么ViewModel能夠在Activity重建了之后也能存活慷吊。上面代碼中ViewModel完成創(chuàng)建后袖裕,我們在Activity中拿到它,并通過它獲取到LiveData溉瓶,然后調(diào)用了observe方法急鳄。
LiveData.java

@MainThread
public void observe(@NonNull LifecycleOwner owner, @NonNull Observer<? super T> observer) {
    assertMainThread("observe");
    if (owner.getLifecycle().getCurrentState() == DESTROYED) {//1
        // ignore
        return;
    }
    LifecycleBoundObserver wrapper = new LifecycleBoundObserver(owner, observer);//2
    ObserverWrapper existing = mObservers.putIfAbsent(observer, wrapper);//3
    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);//4
}

上述邏輯中谤民,1處首先判斷LifecycleOwner是否處于銷毀狀態(tài),如果是疾宏,直接忽略张足;2處創(chuàng)建一個LifecycleBoundObserver包裹了LifecycleOwner和數(shù)據(jù)監(jiān)聽的Observer,并在3處把它通過調(diào)用putIfAbsent存儲到一個Map集合中坎藐。這個地方與之前的LifecycleRegistry類似兢榨,在前面的Lifecycle分析中,LifecycleRegistry通過維護一個Map集合顺饮,保存了所有LifecycleOwner的生命周期監(jiān)聽者。這里類似凌那,LiveData內(nèi)部也維護了一個集合兼雄,保存對它這個數(shù)據(jù)變動的監(jiān)聽者列表,存儲的類型是ObserverWrapper帽蝶。
LifecycleBoundObserver.java

class LifecycleBoundObserver extends ObserverWrapper implements LifecycleEventObserver {
    @NonNull
    final LifecycleOwner mOwner;

    LifecycleBoundObserver(@NonNull LifecycleOwner owner, Observer<? super T> observer) {
        super(observer);
        mOwner = owner;
    }

    @Override
    boolean shouldBeActive() {
        return mOwner.getLifecycle().getCurrentState().isAtLeast(STARTED);
    }

    @Override
    public void onStateChanged(@NonNull LifecycleOwner source,
            @NonNull Lifecycle.Event event) {
        if (mOwner.getLifecycle().getCurrentState() == DESTROYED) {
            removeObserver(mObserver);
            return;
        }
        activeStateChanged(shouldBeActive());
    }

    @Override
    void detachObserver() {
        mOwner.getLifecycle().removeObserver(this);
    }
}

可以看到赦肋,LifecycleBoundObserver本身實現(xiàn)了LifecycleEventObserver接口,而LifecycleEventObserver接口又繼承自LifecycleObserver励稳,因此它本身也是一個LifecycleOwner(或者說Activity等)生命周期的觀察者佃乘。而且在上述代碼4處把它加入到了LifecycleOwner的觀察者集合中。
咦驹尼?本來LiveData通過observe方法添加了一個自身數(shù)據(jù)變動的觀察者到列表中趣避,而添加到列表中的這個對象實例本身又是LifecycleOwner(或者說Activity等)的觀察者。其實看上面LifecycleBoundObserver的構(gòu)造方法中新翎,外界傳入的數(shù)據(jù)變動觀察者交給了父類程帕,也就是ObserverWrapper來完成。
看后面的代碼邏輯地啰,shouldBeActive()愁拭、removeObserver()是不是有點眼熟,沒錯在Lifecycle那篇文章中亏吝,Lifecycle的使用需要我們LifecycleOwner的監(jiān)聽者去主動查詢LifecycleOwner的生命周期狀態(tài)岭埠,然后決定是否繼續(xù)進(jìn)行數(shù)據(jù)的加載(那篇文章中是定位信息的獲取)蔚鸥,如果LifecycleOwner本身處于銷毀狀態(tài)惜论,那么我們應(yīng)該停止數(shù)據(jù)的加載操作。在這里株茶,LiveData把外界傳入的數(shù)據(jù)變動觀察者移除了来涨,也就是說LiveData將不再通知這個Observer數(shù)據(jù)變動了。這也就印證了最開始的LiveData的定義启盛。
到這里蹦掐,我們發(fā)現(xiàn)技羔,原來LifecycleObserver中一些模板式的代碼邏輯,現(xiàn)在都被LiveData幫助完成了卧抗,而我們只需要關(guān)注具體的數(shù)據(jù)獲取就可以了藤滥。

4.3 LiveData的發(fā)布數(shù)據(jù)過程

LiveData通過setValue和postValue來給觀察者發(fā)布數(shù)據(jù),因此這是我們分析的入口社裆。其實postValue本質(zhì)還是調(diào)用了setValue來操作拙绊,因此只分析setValue方法。

LiveData.java

...
@MainThread
protected void setValue(T value) {
    assertMainThread("setValue");//1
    mVersion++;
    mData = value;
    dispatchingValue(null);//2
}

void dispatchingValue(@Nullable ObserverWrapper initiator) {
    if (mDispatchingValue) {
        mDispatchInvalidated = true;
        return;
    }
    mDispatchingValue = true;
    do {
        mDispatchInvalidated = false;
        if (initiator != null) {
            considerNotify(initiator);
            initiator = null;
        } else {
            for (Iterator<Map.Entry<Observer<? super T>, ObserverWrapper>> iterator =
                    mObservers.iteratorWithAdditions(); iterator.hasNext(); ) {
                considerNotify(iterator.next().getValue());//3
                if (mDispatchInvalidated) {
                    break;
                }
            }
        }
    } while (mDispatchInvalidated);
    mDispatchingValue = false;
}

private void considerNotify(ObserverWrapper observer) {
    if (!observer.mActive) {
        return;
    }
    // Check latest state b4 dispatch. Maybe it changed state but we didn't get the event yet.
    //
    // we still first check observer.active to keep it as the entrance for events. So even if
    // the observer moved to an active state, if we've not received that event, we better not
    // notify for a more predictable notification order.
    if (!observer.shouldBeActive()) {//4
        observer.activeStateChanged(false);//5
        return;
    }
    if (observer.mLastVersion >= mVersion) {
        return;
    }
    observer.mLastVersion = mVersion;
    observer.mObserver.onChanged((T) mData);//6
}
...

上面邏輯中泳秀,1處首先判斷調(diào)用的線程是不是主線程标沪,因為setValue方法是主線程調(diào)用的方法;2處開始分發(fā)嗜傅;由于dispatchingValue傳入的是null,因此調(diào)用到3處金句,可以看到是遍歷了內(nèi)部的ObserverWrapper元素,并調(diào)用considerNotify()方法吕嘀;4處通過ObserverWrapper的shouldBeActive方法判斷LifecycleOwner的生命狀態(tài)违寞,實際上是調(diào)用了

mOwner.getLifecycle().getCurrentState().isAtLeast(STARTED);

來獲取狀態(tài),如果不是活躍狀態(tài)偶房,調(diào)用5處以便LiveData來響應(yīng)不同狀態(tài)下的處理趁曼,并直接返回,這里可以看出棕洋,如果LifecycleOwner沒有處于活動狀態(tài)的話挡闰,后續(xù)邏輯不再執(zhí)行,直接返回掰盘,進(jìn)一步驗證了開頭LiveData的生命周期感知能力尿这;6處調(diào)用到實際的Observer的onChanged方法,即我們Activity中創(chuàng)建的Observer中的邏輯中庆杜。

5.總結(jié)

5.1 整體邏輯都分析完成了射众,總結(jié)一下大概類之間的關(guān)系

LiveData、ViewModel和Lifecycle.png

5.2 來檢驗一下自己

Q:LiveData是什么晃财?
A:LiveData是一個具有生命周期感知能力的數(shù)據(jù)持有者叨橱,對于數(shù)據(jù)變動的觀察者,會有選擇性地針對處在活躍狀態(tài)的觀察者發(fā)布數(shù)據(jù)断盛。

Q:LiveData本身可以直接在Activity使用罗洗,為什么需要ViewModel這中間的一層?
A:1.能夠避免Activity或Fragment中過于龐大钢猛,使得它們只負(fù)責(zé)展示數(shù)據(jù)伙菜,而存儲數(shù)據(jù)的任務(wù)交給了LiveData,而LiveData存儲在ViewModel中; 2.能夠把LiveData與Activity或Fragment實例分離命迈,并保證它們配置更改不會影響數(shù)據(jù)生命周期

Q:ViewModel是如何保證配置更改的生命周期的贩绕?
A:利用了Activity中的onRetainNonConfigurationInstance來存儲數(shù)據(jù)火的,getLastNonConfigurationInstance來獲取數(shù)據(jù)。在Activity中實現(xiàn)了ViewModelStoreOwner接口淑倾,內(nèi)部創(chuàng)建了一個ViewModelStore馏鹤,并根據(jù)前面兩個方法在配置更改時保存和獲取。ViewModelStoreOwner中維護了一個ViewModel的HashMap集合娇哆,創(chuàng)建ViewModel時首先通過ViewModelProvider會去判斷ViewModelStore中是否已經(jīng)存在該ViewModel湃累,存在則直接獲取,否則通過構(gòu)建工廠創(chuàng)建碍讨。在Activity內(nèi)部添加了LifecycleOwner的生命周期觀察者治力,并在Activity等生命周期進(jìn)入Finished狀態(tài)時,會遍歷ViewModelStoreOwner的clear方法來清理ViewModel勃黍。

Q:LiveData如何保證對不活動的觀察者不發(fā)送數(shù)據(jù)琴许?
A:首先在對LiveData添加觀察者時,會把這個觀察者包裹在一個LifecycleBoundObserver中溉躲,該類實現(xiàn)了LifecycleEventObserver接口,而LifecycleEventObserver實現(xiàn)了LifecycleObserver接口益兄。之后把包裹對象向LifecycleOwner注冊锻梳,這樣便監(jiān)聽了Activity等的生命周期,并在監(jiān)聽方法中判斷ON_DESTROY事件净捅,在內(nèi)部移除了對生命周期的監(jiān)聽疑枯;此外,在LiveData發(fā)布數(shù)據(jù)后蛔六,會遍歷LifecycleBoundObserver(代碼中時ObserverWrapper荆永,實際對象類型是LifecycleBoundObserver),并通過內(nèi)部持有的LifecycleOwner獲取當(dāng)前生命周期狀態(tài)国章,如果不屬于活躍狀態(tài)具钥,將不會繼續(xù)執(zhí)行發(fā)送數(shù)據(jù),當(dāng)它重新處于活躍狀態(tài)時液兽,下次發(fā)布數(shù)據(jù)變動骂删,還會通知到它。

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末四啰,一起剝皮案震驚了整個濱河市宁玫,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌柑晒,老刑警劉巖欧瘪,帶你破解...
    沈念sama閱讀 218,941評論 6 508
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場離奇詭異匙赞,居然都是意外死亡佛掖,警方通過查閱死者的電腦和手機妖碉,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 93,397評論 3 395
  • 文/潘曉璐 我一進(jìn)店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來苦囱,“玉大人嗅绸,你說我怎么就攤上這事∷和” “怎么了鱼鸠?”我有些...
    開封第一講書人閱讀 165,345評論 0 356
  • 文/不壞的土叔 我叫張陵,是天一觀的道長羹铅。 經(jīng)常有香客問我蚀狰,道長,這世上最難降的妖魔是什么职员? 我笑而不...
    開封第一講書人閱讀 58,851評論 1 295
  • 正文 為了忘掉前任麻蹋,我火速辦了婚禮,結(jié)果婚禮上焊切,老公的妹妹穿的比我還像新娘扮授。我一直安慰自己,他們只是感情好专肪,可當(dāng)我...
    茶點故事閱讀 67,868評論 6 392
  • 文/花漫 我一把揭開白布刹勃。 她就那樣靜靜地躺著,像睡著了一般嚎尤。 火紅的嫁衣襯著肌膚如雪荔仁。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 51,688評論 1 305
  • 那天芽死,我揣著相機與錄音乏梁,去河邊找鬼。 笑死关贵,一個胖子當(dāng)著我的面吹牛遇骑,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播揖曾,決...
    沈念sama閱讀 40,414評論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼质蕉,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了翩肌?” 一聲冷哼從身側(cè)響起模暗,我...
    開封第一講書人閱讀 39,319評論 0 276
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎念祭,沒想到半個月后兑宇,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 45,775評論 1 315
  • 正文 獨居荒郊野嶺守林人離奇死亡粱坤,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 37,945評論 3 336
  • 正文 我和宋清朗相戀三年隶糕,在試婚紗的時候發(fā)現(xiàn)自己被綠了瓷产。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 40,096評論 1 350
  • 序言:一個原本活蹦亂跳的男人離奇死亡枚驻,死狀恐怖濒旦,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情再登,我是刑警寧澤尔邓,帶...
    沈念sama閱讀 35,789評論 5 346
  • 正文 年R本政府宣布,位于F島的核電站锉矢,受9級特大地震影響梯嗽,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜沽损,卻給世界環(huán)境...
    茶點故事閱讀 41,437評論 3 331
  • 文/蒙蒙 一灯节、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧绵估,春花似錦炎疆、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,993評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至躏救,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間螟蒸,已是汗流浹背盒使。 一陣腳步聲響...
    開封第一講書人閱讀 33,107評論 1 271
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留七嫌,地道東北人少办。 一個月前我還...
    沈念sama閱讀 48,308評論 3 372
  • 正文 我出身青樓,卻偏偏與公主長得像诵原,于是被迫代替她去往敵國和親英妓。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點故事閱讀 45,037評論 2 355