JetPackのLiveData使用とソースコード分析
LiveDataはLifecycleに基づいて発展してきましたが、例を見てみると、ViewModelを借りる必要があることがわかります.例を見てみましょう.
実行後、テキストをクリックすると、テキストの値が変わります.それはどのように実現されたのか、はっきり言っても観察者モードなのか、なぜLiveDataがメモリ漏洩を効果的に回避できるのか.コードを読みに来ました
ViewModelProvidersというクラスのメソッドは時代遅れと表記されていますが、ポイントしてみると、実はnewがViewModelProviderオブジェクトであることに気づきました.私たちが書いたように、AppCompatActivityはComponentActivityを継承し、ComponentActivityはViewModelStoreOwnerというインタフェースを実現し、コアは1行のコードです
ViewModelStoreクラスの論理も簡単で、ViewModelを格納するメンバー変数HashMapがあります.ComponentActivityもHasDefaultViewModelProviderFactoryインタフェースを実現し、コアも1行のコードです
SavedStateViewModelFactoryの論理は少し多いですが、名前を見ると工場モードであることがわかり、構造方法は最終的に実行されます.
この線はまずこれを見て、SavedStateViewModelFactoryの構造方法の中にmFactoryがあることを覚えておいて、私たちは引き続きViewModelProviderのget()方法を見ます
これは簡略化されたコードで、mViewModelStoreはViewModelStoreタイプで、変数値を格納するために使用され、初めて取得したviewModelはnullです.mFactoryはSavedStateViewModelFactoryで、KeyedFactoryクラスを継承しているので、create(key,modelClass)という方法を見てみましょう.keyは文字列タイプで、modelClassはclassタイプです.
最終的にはここまで実行されます.ここでmFactoryはViewModelProviderの内部クラスAndroidViewModelFactoryで、またViewModelProviderクラスを迂回し直しました.見てみましょう.
注意して、この中は反射で、Applicationパラメータ付きの構造方法を選択して、異常が投げ出されたらsuper()方法を実行します.Android ViewModelFactoryのベースクラスは NewInstanceFactory、その方法を見てみましょう
反射でもあり、パラメトリック構造であり、viewModelを取得した後、mViewModelStoreのmapセットに追加します.ここから、NameViewModelはViewModelを継承し、public、すなわちデフォルトのデフォルトの無パラメトリック構造を保証する必要があることがわかります.上記ではLDActivityでNameViewModelタイプのオブジェクトが作成されていますが、LDActivity 1またはLDActivity 2でもこの方法が使用されている場合、得られるNameViewModelオブジェクトは同じです.mViewModelStoreのmapがキャッシュされているため、データ共有を実現できます.NameViewModelは偽の単利のような存在です.
MutableLiveDataはLiveDataに継承され、MutableLiveDataのコードは比較的少なく、ただ移行の役割を果たすだけで、主なロジックはやはりLiveDataの中で、observe()はリスニングを追加する方法である.
まず、現在のスレッドがUIスレッドであるかどうかをチェックし、最終的にはDefaultTaskExecutorクラスがチェックしています.スレッドプールとHandlerが入っています.興味があるのは見てみましょう.LifecycleOwnerは前章で述べたもので、ここでライフサイクルをチェックするために使用され、ActivityがonDestroy()を通過した後、この方法はここまでで、下に実行されません.LifecycleBoundObserverはLifecycleEventObserverインタフェースを実現し、wrapperもLifecycleのライフサイクルリスニングに追加されました.このときActivityのライフサイクルが実行されるにつれて、LifecycleBoundObserverでもコールバックが受け入れられます.
この方法では,Lifecycleのstate状態がDESTROYEDであればmObserverリスニングを削除することで,後続のデータが変化してもmObserverが実行されないことを保証し,不要なメモリリークや空のポインタなどの問題を回避できるという判断もある.shouldBeActive()で生存するかどうかを判断します.ここではLifecycleの状態がSTARTED以上であるかどうかを判断します.activeStateChanged()メソッドを見てみましょう.
この方法はコードが面白いですが、newActiveの値が同じなら、一度だけ実行します.最初はmActiveがfalseの場合 新Activeがtrueの場合、mActiveCountの初期値は0、wasInactiveがtrueの場合、実行されます onActive()メソッドは、次の呼び出しでnewActiveがtrueの場合、直接returnします.新Activeがfalseの場合、mActiveCount値は+1と-1の後、再び0に戻り、onInactive()メソッドが実行されます.つまり、この2つの方法はペアで現れています.この2つの方法は、ActivityのonStart()とonStop()の方法に対応しています.LiveDataをカスタマイズするときに、この2つの方法を書き直して、自分の論理的な操作をすることができます.最後にdispatchingValue(this)メソッドを見てみましょう.これはmActiveがtrueの場合にのみ呼び出されます.
これは簡略化されたコードであり,considerNotify()メソッドではmVersionが0,observer.mLastVersion値が-1であるため,このメソッドもreturnとなる.LiveDataのobserve()メソッド解析はここまでですので、見てみましょう setValue()メソッドとpostValue()メソッドは、コードを見て、setValue()はUIスレッドで呼び出さなければなりません.postValue()はHandlerでスレッドをUIスレッドに切り替え、setValue()メソッドを呼び出します.
また パラメータがnullであるため、dispatchingValue()は
Observers()メソッドでは、mObserversにLifecycleBoundObserverが追加されています.このメソッドでは、それを巡り、mObserversに追加されたLifecycleBoundObserverオブジェクトを取り出し、considerNotify()メソッドを呼び出します.
Mobsserver.mObserverは我々LDActivityのnameObserverであり、このときonChanged()メソッドが呼び出され、このときmDataはsetValue(「death_pohuai」)メソッドの「death_pohuai」であり、nameObserverの実装方法:nameTextView.setText(newName)であり、これが我々が見た現象である.
MediatorLiveDataはMutableLiveDataのサブクラスで、addSource(LiveData source,Observer super S>onChanged)メソッドを提供しています.sourceというオブジェクトに値が変化すれば、onChangedはすぐにコールバックを実行するという意味ですが、どのように実現されるのでしょうか.この方法を見て
ここでhasActiveObservers()メソッドはfalseであり,最初の2行のコードだけを見てSourceオブジェクトを作成し,mSourcesセットに追加し,Sourceというクラスを見てObserverインタフェースを実現した.
またコールバックであり、plug()でobserveForever()メソッドがコールバックを登録し、removeObserver()がコールバックを削除します.前述したように、LiveDataはActivityのライフサイクルとともにonActive()とonInactive()メソッドを実行します.MediatorLiveDataのコードを見てみましょう.
やはり,mSourcesからSourceを取得し,plug()とunplug()メソッドを呼び出した.LiveDataオブジェクトのsetValue()割り当てを呼び出すと、SourceのonChanged()メソッドがトリガーされ、mObserverのonChanged()メソッドがコールバックされます.これでこの機能が実現して、個人的にはこの機能は少し鶏の肋骨だと思います.注意深い友人は、plug()メソッドではLiveDataがobserveForever()メソッドを使用していることに気づきますが、observe()メソッドとはどのような違いがありますか?
ここで作成するオブジェクトはAlwaysActiveObserverであり、アクティブにactiveStateChanged(true)メソッドが呼び出されます.パラメータはtrueです.AlwaysActiveObserverクラスを見てください.
AlwaysActiveObserverはObserverWrapperを継承しただけで、LifecycleEventObserverインタフェースを実現していないので、Activityのライフサイクルの変化を受け入れないリスニングイベントがあるのは当然です.また,shouldBeActive()メソッドが返す値は一定のtrueであり,activeStateChanged(true)メソッドを加えると,observeForever()メソッドを呼び出すと既にactiveStateChanged(true)メソッドが実行されており,このときonActive()メソッドが実行される.removeObserver()メソッドを見てみましょう
ActiveStateChanged(false)メソッドも呼び出されます.値はfalseです.onInactive()メソッドが実行されます.実ははっきり言って、全体が観察者モードの使用です.
public class LDActivity extends AppCompatActivity implements View.OnClickListener{
private final static String TAG = "LDActivity";
private NameViewModel model;
TextView nameTextView;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_ld);
nameTextView = findViewById(R.id.tv_user_name);
model = new ViewModelProvider(this).get(NameViewModel.class);
// model = ViewModelProviders.of(this).get(NameViewModel.class);
Observer nameObserver = new Observer() {
@Override
public void onChanged(@Nullable final String newName) {
nameTextView.setText(newName);
}
};
model.getCurrentName().observe(this, nameObserver);
nameTextView.setOnClickListener(this);
}
@Override
public void onClick(View v) {
switch (v.getId()){
case R.id.tv_user_name:
model.getCurrentName().setValue("death_pohuai");
break;
}
}
}
xml: activity_ld
public class NameViewModel extends ViewModel {
private MutableLiveData currentName;
public MutableLiveData getCurrentName() {
if (currentName == null) {
currentName = new MutableLiveData<>();
}
return currentName;
}
}
実行後、テキストをクリックすると、テキストの値が変わります.それはどのように実現されたのか、はっきり言っても観察者モードなのか、なぜLiveDataがメモリ漏洩を効果的に回避できるのか.コードを読みに来ました
ViewModelProvidersというクラスのメソッドは時代遅れと表記されていますが、ポイントしてみると、実はnewがViewModelProviderオブジェクトであることに気づきました.私たちが書いたように、AppCompatActivityはComponentActivityを継承し、ComponentActivityはViewModelStoreOwnerというインタフェースを実現し、コアは1行のコードです
@Override
public ViewModelStore getViewModelStore() {
...
if (mViewModelStore == null) {
mViewModelStore = new ViewModelStore();
}
return mViewModelStore;
}
ViewModelStoreクラスの論理も簡単で、ViewModelを格納するメンバー変数HashMapがあります.ComponentActivityもHasDefaultViewModelProviderFactoryインタフェースを実現し、コアも1行のコードです
@Override
public ViewModelProvider.Factory getDefaultViewModelProviderFactory() {
...
mDefaultFactory = new SavedStateViewModelFactory(getApplication(), this,getIntent() != null ? getIntent().getExtras() : null);
return mDefaultFactory;
}
SavedStateViewModelFactoryの論理は少し多いですが、名前を見ると工場モードであることがわかり、構造方法は最終的に実行されます.
public SavedStateViewModelFactory(@NonNull Application application,
@NonNull SavedStateRegistryOwner owner,
@Nullable Bundle defaultArgs) {
mSavedStateRegistry = owner.getSavedStateRegistry();
mLifecycle = owner.getLifecycle();
mDefaultArgs = defaultArgs;
mApplication = application;
mFactory = ViewModelProvider.AndroidViewModelFactory.getInstance(application);
}
この線はまずこれを見て、SavedStateViewModelFactoryの構造方法の中にmFactoryがあることを覚えておいて、私たちは引き続きViewModelProviderのget()方法を見ます
@MainThread
public T get(@NonNull Class modelClass) {
String canonicalName = modelClass.getCanonicalName();
if (canonicalName == null) {
throw new IllegalArgumentException("Local and anonymous classes can not be ViewModels");
}
return get(DEFAULT_KEY + ":" + canonicalName, modelClass);
}
@MainThread
public T get(@NonNull String key, @NonNull Class modelClass) {
ViewModel viewModel = mViewModelStore.get(key);
...
if (mFactory instanceof KeyedFactory) {
viewModel = ((KeyedFactory) (mFactory)).create(key, modelClass);
} else {
viewModel = (mFactory).create(modelClass);
}
mViewModelStore.put(key, viewModel);
return (T) viewModel;
}
これは簡略化されたコードで、mViewModelStoreはViewModelStoreタイプで、変数値を格納するために使用され、初めて取得したviewModelはnullです.mFactoryはSavedStateViewModelFactoryで、KeyedFactoryクラスを継承しているので、create(key,modelClass)という方法を見てみましょう.keyは文字列タイプで、modelClassはclassタイプです.
@Override
public T create(@NonNull String key, @NonNull Class modelClass) {
...
if (constructor == null) {
return mFactory.create(modelClass);
}
...
}
最終的にはここまで実行されます.ここでmFactoryはViewModelProviderの内部クラスAndroidViewModelFactoryで、またViewModelProviderクラスを迂回し直しました.見てみましょう.
@Override
public T create(@NonNull Class modelClass) {
if (AndroidViewModel.class.isAssignableFrom(modelClass)) {
try {
return modelClass.getConstructor(Application.class).newInstance(mApplication);
} catch (NoSuchMethodException e) {
throw new RuntimeException("Cannot create an instance of " + modelClass, e);
} catch (IllegalAccessException e) {
throw new RuntimeException("Cannot create an instance of " + modelClass, e);
} catch (InstantiationException e) {
throw new RuntimeException("Cannot create an instance of " + modelClass, e);
} catch (InvocationTargetException e) {
throw new RuntimeException("Cannot create an instance of " + modelClass, e);
}
}
return super.create(modelClass);
}
注意して、この中は反射で、Applicationパラメータ付きの構造方法を選択して、異常が投げ出されたらsuper()方法を実行します.Android ViewModelFactoryのベースクラスは NewInstanceFactory、その方法を見てみましょう
@Override
public T create(@NonNull Class modelClass) {
try {
return modelClass.newInstance();
} catch (InstantiationException e) {
throw new RuntimeException("Cannot create an instance of " + modelClass, e);
} catch (IllegalAccessException e) {
throw new RuntimeException("Cannot create an instance of " + modelClass, e);
}
}
反射でもあり、パラメトリック構造であり、viewModelを取得した後、mViewModelStoreのmapセットに追加します.ここから、NameViewModelはViewModelを継承し、public、すなわちデフォルトのデフォルトの無パラメトリック構造を保証する必要があることがわかります.上記ではLDActivityでNameViewModelタイプのオブジェクトが作成されていますが、LDActivity 1またはLDActivity 2でもこの方法が使用されている場合、得られるNameViewModelオブジェクトは同じです.mViewModelStoreのmapがキャッシュされているため、データ共有を実現できます.NameViewModelは偽の単利のような存在です.
MutableLiveDataはLiveDataに継承され、MutableLiveDataのコードは比較的少なく、ただ移行の役割を果たすだけで、主なロジックはやはりLiveDataの中で、observe()はリスニングを追加する方法である.
@MainThread
public void observe(@NonNull LifecycleOwner owner, @NonNull Observer super T> observer) {
assertMainThread("observe");
if (owner.getLifecycle().getCurrentState() == DESTROYED) {
return;
}
LifecycleBoundObserver wrapper = new LifecycleBoundObserver(owner, observer);
ObserverWrapper existing = mObservers.putIfAbsent(observer, wrapper);
...
owner.getLifecycle().addObserver(wrapper);
}
static void assertMainThread(String methodName) {
if (!ArchTaskExecutor.getInstance().isMainThread()) {
throw new IllegalStateException("Cannot invoke " + methodName + " on a background"
+ " thread");
}
}
まず、現在のスレッドがUIスレッドであるかどうかをチェックし、最終的にはDefaultTaskExecutorクラスがチェックしています.スレッドプールとHandlerが入っています.興味があるのは見てみましょう.LifecycleOwnerは前章で述べたもので、ここでライフサイクルをチェックするために使用され、ActivityがonDestroy()を通過した後、この方法はここまでで、下に実行されません.LifecycleBoundObserverはLifecycleEventObserverインタフェースを実現し、wrapperもLifecycleのライフサイクルリスニングに追加されました.このときActivityのライフサイクルが実行されるにつれて、LifecycleBoundObserverでもコールバックが受け入れられます.
@Override
public void onStateChanged(@NonNull LifecycleOwner source,
@NonNull Lifecycle.Event event) {
if (mOwner.getLifecycle().getCurrentState() == DESTROYED) {
removeObserver(mObserver);
return;
}
activeStateChanged(shouldBeActive());
}
@Override
boolean shouldBeActive() {
return mOwner.getLifecycle().getCurrentState().isAtLeast(STARTED);
}
この方法では,Lifecycleのstate状態がDESTROYEDであればmObserverリスニングを削除することで,後続のデータが変化してもmObserverが実行されないことを保証し,不要なメモリリークや空のポインタなどの問題を回避できるという判断もある.shouldBeActive()で生存するかどうかを判断します.ここではLifecycleの状態がSTARTED以上であるかどうかを判断します.activeStateChanged()メソッドを見てみましょう.
void activeStateChanged(boolean newActive) {
if (newActive == mActive) {
return;
}
mActive = newActive;
boolean wasInactive = LiveData.this.mActiveCount == 0;
LiveData.this.mActiveCount += mActive ? 1 : -1;
if (wasInactive && mActive) {
onActive();
}
if (LiveData.this.mActiveCount == 0 && !mActive) {
onInactive();
}
if (mActive) {
dispatchingValue(this);
}
}
この方法はコードが面白いですが、newActiveの値が同じなら、一度だけ実行します.最初はmActiveがfalseの場合 新Activeがtrueの場合、mActiveCountの初期値は0、wasInactiveがtrueの場合、実行されます onActive()メソッドは、次の呼び出しでnewActiveがtrueの場合、直接returnします.新Activeがfalseの場合、mActiveCount値は+1と-1の後、再び0に戻り、onInactive()メソッドが実行されます.つまり、この2つの方法はペアで現れています.この2つの方法は、ActivityのonStart()とonStop()の方法に対応しています.LiveDataをカスタマイズするときに、この2つの方法を書き直して、自分の論理的な操作をすることができます.最後にdispatchingValue(this)メソッドを見てみましょう.これはmActiveがtrueの場合にのみ呼び出されます.
void dispatchingValue(@Nullable ObserverWrapper initiator) {
...
considerNotify(initiator);
...
}
private void considerNotify(ObserverWrapper observer) {
if (!observer.mActive) {
return;
}
if (!observer.shouldBeActive()) {
observer.activeStateChanged(false);
return;
}
if (observer.mLastVersion >= mVersion) {
return;
}
observer.mLastVersion = mVersion;
observer.mObserver.onChanged((T) mData);
}
これは簡略化されたコードであり,considerNotify()メソッドではmVersionが0,observer.mLastVersion値が-1であるため,このメソッドもreturnとなる.LiveDataのobserve()メソッド解析はここまでですので、見てみましょう setValue()メソッドとpostValue()メソッドは、コードを見て、setValue()はUIスレッドで呼び出さなければなりません.postValue()はHandlerでスレッドをUIスレッドに切り替え、setValue()メソッドを呼び出します.
@MainThread
protected void setValue(T value) {
assertMainThread("setValue");
mVersion++;
mData = value;
dispatchingValue(null);
}
また パラメータがnullであるため、dispatchingValue()は
void dispatchingValue(@Nullable ObserverWrapper initiator) {
...
for (Iterator, ObserverWrapper>> iterator =
mObservers.iteratorWithAdditions(); iterator.hasNext(); ) {
considerNotify(iterator.next().getValue());
if (mDispatchInvalidated) {
break;
}
}
...
}
Observers()メソッドでは、mObserversにLifecycleBoundObserverが追加されています.このメソッドでは、それを巡り、mObserversに追加されたLifecycleBoundObserverオブジェクトを取り出し、considerNotify()メソッドを呼び出します.
private void considerNotify(ObserverWrapper observer) {
...
observer.mLastVersion = mVersion;
observer.mObserver.onChanged((T) mData);
}
Mobsserver.mObserverは我々LDActivityのnameObserverであり、このときonChanged()メソッドが呼び出され、このときmDataはsetValue(「death_pohuai」)メソッドの「death_pohuai」であり、nameObserverの実装方法:nameTextView.setText(newName)であり、これが我々が見た現象である.
MediatorLiveDataはMutableLiveDataのサブクラスで、addSource(LiveData source,Observer super S>onChanged)メソッドを提供しています.sourceというオブジェクトに値が変化すれば、onChangedはすぐにコールバックを実行するという意味ですが、どのように実現されるのでしょうか.この方法を見て
@MainThread
public void addSource(@NonNull LiveData source, @NonNull Observer super S> onChanged) {
Source e = new Source<>(source, onChanged);
Source> existing = mSources.putIfAbsent(source, e);
if (existing != null && existing.mObserver != onChanged) {
throw new IllegalArgumentException(
"This source was already added with the different observer");
}
if (existing != null) {
return;
}
if (hasActiveObservers()) {
e.plug();
}
}
ここでhasActiveObservers()メソッドはfalseであり,最初の2行のコードだけを見てSourceオブジェクトを作成し,mSourcesセットに追加し,Sourceというクラスを見てObserverインタフェースを実現した.
private static class Source implements Observer {
final LiveData mLiveData;
final Observer super V> mObserver;
int mVersion = START_VERSION;
Source(LiveData liveData, final Observer super V> observer) {
mLiveData = liveData;
mObserver = observer;
}
void plug() {
mLiveData.observeForever(this);
}
void unplug() {
mLiveData.removeObserver(this);
}
@Override
public void onChanged(@Nullable V v) {
if (mVersion != mLiveData.getVersion()) {
mVersion = mLiveData.getVersion();
mObserver.onChanged(v);
}
}
}
またコールバックであり、plug()でobserveForever()メソッドがコールバックを登録し、removeObserver()がコールバックを削除します.前述したように、LiveDataはActivityのライフサイクルとともにonActive()とonInactive()メソッドを実行します.MediatorLiveDataのコードを見てみましょう.
@CallSuper
@Override
protected void onActive() {
for (Map.Entry, Source>> source : mSources) {
source.getValue().plug();
}
}
@CallSuper
@Override
protected void onInactive() {
for (Map.Entry, Source>> source : mSources) {
source.getValue().unplug();
}
}
やはり,mSourcesからSourceを取得し,plug()とunplug()メソッドを呼び出した.LiveDataオブジェクトのsetValue()割り当てを呼び出すと、SourceのonChanged()メソッドがトリガーされ、mObserverのonChanged()メソッドがコールバックされます.これでこの機能が実現して、個人的にはこの機能は少し鶏の肋骨だと思います.注意深い友人は、plug()メソッドではLiveDataがobserveForever()メソッドを使用していることに気づきますが、observe()メソッドとはどのような違いがありますか?
@MainThread
public void observeForever(@NonNull Observer super T> observer) {
assertMainThread("observeForever");
AlwaysActiveObserver wrapper = new AlwaysActiveObserver(observer);
ObserverWrapper existing = mObservers.putIfAbsent(observer, wrapper);
if (existing instanceof LiveData.LifecycleBoundObserver) {
throw new IllegalArgumentException("Cannot add the same observer"
+ " with different lifecycles");
}
if (existing != null) {
return;
}
wrapper.activeStateChanged(true);
}
ここで作成するオブジェクトはAlwaysActiveObserverであり、アクティブにactiveStateChanged(true)メソッドが呼び出されます.パラメータはtrueです.AlwaysActiveObserverクラスを見てください.
private class AlwaysActiveObserver extends ObserverWrapper {
AlwaysActiveObserver(Observer super T> observer) {
super(observer);
}
@Override
boolean shouldBeActive() {
return true;
}
}
AlwaysActiveObserverはObserverWrapperを継承しただけで、LifecycleEventObserverインタフェースを実現していないので、Activityのライフサイクルの変化を受け入れないリスニングイベントがあるのは当然です.また,shouldBeActive()メソッドが返す値は一定のtrueであり,activeStateChanged(true)メソッドを加えると,observeForever()メソッドを呼び出すと既にactiveStateChanged(true)メソッドが実行されており,このときonActive()メソッドが実行される.removeObserver()メソッドを見てみましょう
@MainThread
public void removeObserver(@NonNull final Observer super T> observer) {
assertMainThread("removeObserver");
ObserverWrapper removed = mObservers.remove(observer);
if (removed == null) {
return;
}
removed.detachObserver();
removed.activeStateChanged(false);
}
ActiveStateChanged(false)メソッドも呼び出されます.値はfalseです.onInactive()メソッドが実行されます.実ははっきり言って、全体が観察者モードの使用です.