JetPackのViewModel原理学習
5207 ワード
JetPackのViewModelの位置づけは、管理インタフェース(ActivityまたはFragment)データを格納するためのクラスであり、ViewModelのデータはLiveDataによって格納することができる.ViewModel全体のコードは多くなく、全部で100行以上です.主にView Modelがkotlinのコラボレーションとどのように結合して使用されるか、およびView ModelがActivity/Fragmentのライフサイクルをどのように関連付けているかを学び、Activity/Fragmentのライフサイクルが終了した後、メモリの漏洩を防ぐためにクリーンアップ作業を行います.
拡張プロパティはget()メソッドを複写し、主にKeyに基づいてViewModelの
以下に、ViewModelに関連するコードを示します. 格納されています. viewModelScopeが存在しない場合、CloseableCoroutineScopeのオブジェクトを作成し、 を入れることを試みます. を行う. ViewModelのclear()メソッドでは、 が呼び出されます.
上のViewModelのソースコードではメモリ漏洩防止の操作がViewModelのclear()メソッドで行われていることが多く見られますが、この考え方に沿って遡り、clear()メソッドはどこで呼び出されたのかを遡ることができます.上へ遡ると、ViewModelStoreのclear()メソッドで呼び出されたことがわかります.
注記ViewModelStoreというクラスは
AndroidxのComponentActivityはLifecycleのライフサイクルの変化を監視し、ライフサイクルではON_DESTROYの場合は、ViewModelStoreのclear()メソッドを呼び出します.
ActivityライフサイクルがONになるまでDESTROY->View ModelStore#clear()メソッドの呼び出し->View ModelStore内のすべてのView Modelを巡り、View Model#clear()メソッドの呼び出し->View Model内のすべてのCloseableオブジェクトを呼び出すcloseメソッド&コールバックonCleared()メソッド.
tips:普段はViewModelで消去/逆登録の操作をする必要がある場合はonCleared()メソッドを複写し、このメソッドで操作することができます
ViewModelでのコパスの使用
androidx.lifecycle:lifecycle-viewModel-ktx
は2.1.0以降にViewModelを拡張し、viewModelScope
の拡張属性を提供する.そのため、ViewModelでいくつかのコラボレーション操作を行うことができます.private const val JOB_KEY = "androidx.lifecycle.ViewModelCoroutineScope.JOB_KEY"
val ViewModel.viewModelScope: CoroutineScope
get() {
val scope: CoroutineScope? = this.getTag(JOB_KEY)
if (scope != null) {
return scope
}
return setTagIfAbsent(JOB_KEY,
CloseableCoroutineScope(SupervisorJob() + Dispatchers.Main.immediate))
}
拡張プロパティはget()メソッドを複写し、主にKeyに基づいてViewModelの
mBagOfTags( Map)
から対応するCoroutineScopeを取りに行き、取り出せなければCloseableCoroutineScope
を作成し、ViewModelのmBagOfTags
に配置します.internal class CloseableCoroutineScope(context: CoroutineContext) : Closeable, CoroutineScope {
override val coroutineContext: CoroutineContext = context
override fun close() {
coroutineContext.cancel()
}
}
CloseableCoroutineScope
はCloseableインターフェースを実装し、closeメソッドにおいて、コヒーレントのJobに対してcancelメソッドを呼び出して、コヒーレントのJobをキャンセルする.以下に、ViewModelに関連するコードを示します.
mBagOfTags
はHashMapで、私たちのviewModelScope属性はこのMapにmBagOfTags
というMapにviewModelScope
はCloseableCoroutineScopeのオブジェクトであり、このクラスはCloseableインタフェースを実現し、close法においてコヒーレントなJobに対してcancel mBagOfTags
のすべてのCloseableオブジェクトのclose()メソッドpublic abstract class ViewModel {
private final Map mBagOfTags = new HashMap<>();
private volatile boolean mCleared = false;
@MainThread
final void clear() {
mCleared = true;
if (mBagOfTags != null) {
synchronized (mBagOfTags) {
// Map Closeable , close ,
for (Object value : mBagOfTags.values()) {
closeWithRuntimeException(value);
}
}
}
onCleared();
}
@SuppressWarnings("unchecked")
T setTagIfAbsent(String key, T newValue) {
T previous;
synchronized (mBagOfTags) {
previous = (T) mBagOfTags.get(key);
if (previous == null) {
mBagOfTags.put(key, newValue);
}
}
T result = previous == null ? newValue : previous;
if (mCleared) {
closeWithRuntimeException(result);
}
return result;
}
T getTag(String key) {
if (mBagOfTags == null) {
return null;
}
synchronized (mBagOfTags) {
return (T) mBagOfTags.get(key);
}
}
private static void closeWithRuntimeException(Object obj) {
if (obj instanceof Closeable) {
try {
((Closeable) obj).close();
} catch (IOException e) {
throw new RuntimeException(e);
}
}
}
}
ViewModel関連コンポーネントのライフサイクル
上のViewModelのソースコードではメモリ漏洩防止の操作がViewModelのclear()メソッドで行われていることが多く見られますが、この考え方に沿って遡り、clear()メソッドはどこで呼び出されたのかを遡ることができます.上へ遡ると、ViewModelStoreのclear()メソッドで呼び出されたことがわかります.
// Class to store {@code ViewModels}.
public class ViewModelStore {
private final HashMap mMap = new HashMap<>();
/**
* Clears internal storage and notifies ViewModels that they are no longer used.
*/
public final void clear() {
for (ViewModel vm : mMap.values()) {
vm.clear();
}
mMap.clear();
}
}
注記ViewModelStoreというクラスは
ViewModel
を格納するために使用され、ViewModelはHashMap
に格納されます.では、ViewModelStoreのclear()メソッドはどこで呼び出されますか?ここでActivityの状況を分析します.public ComponentActivity() {
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();
}
}
}
});
}
AndroidxのComponentActivityはLifecycleのライフサイクルの変化を監視し、ライフサイクルではON_DESTROYの場合は、ViewModelStoreのclear()メソッドを呼び出します.
ActivityライフサイクルがONになるまでDESTROY->View ModelStore#clear()メソッドの呼び出し->View ModelStore内のすべてのView Modelを巡り、View Model#clear()メソッドの呼び出し->View Model内のすべてのCloseableオブジェクトを呼び出すcloseメソッド&コールバックonCleared()メソッド.
tips:普段はViewModelで消去/逆登録の操作をする必要がある場合はonCleared()メソッドを複写し、このメソッドで操作することができます