如何手动清除特定的视图模型?

Mar*_*tin 5 android mvvm android-viewmodel

据我了解,当我们在片段中调用此代码时,我们将从 Activity ViewModelStore 获得一个视图模型实例:

viewModel = ViewModelProviders.of(activity!!).get(SharedViewModel::class.java)
Run Code Online (Sandbox Code Playgroud)

当fragment结束其生命周期时,该viewmodel的实例将存在于ViewModelStore中,直到activity销毁。ViewModelStore 有一个clear()方法,但它会清除其中的所有视图模型。有什么方法可以清除特定的 ViewModel 吗?

另一个解决方案是将 ViewModel 的范围限定为父片段,但是我们如何通过 ViewModelProviders.of() 初始化另一个片段中的 ViewModel?我应该将片段或视图模型实例传递给下一个片段吗?

Mos*_*jad 4

有一种黑客方法可以清除特定ViewModel实例,您应该ViewModel使用如下所述的自定义创建实例key,并且为了清除它,您应该创建另一个实例(具有不同的ViewModel类,例如EmptyViewModel类)但具有相同的key.

ShopFragment 类:

class shopFragment : BaseFragment() {

    fun getViewModel() : ShopViewModel {
        return ViewModelProviders.of(activity!!).get(ShopViewModel.KEY, ShopViewModel::class.java)
    }

    fun clearViewModel() {
        ViewModelProviders.of(activity!!).get(ShopViewModel.KEY, EmptyViewModel::class.java) 
    }

    // Fragment logic ...

}
Run Code Online (Sandbox Code Playgroud)

ShopViewModel 类:

class ShopViewModel(application: Application) : AndroidViewModel(application) {

    companion object {
        const val KEY = "ShopViewModel"
    }

    // view model logic ...

}
Run Code Online (Sandbox Code Playgroud)

EmptyViewModel 这是一个虚拟 ViewModel 类:

class EmptyViewModel() : ViewModel() {
    // A dummy view model!
}
Run Code Online (Sandbox Code Playgroud)

魔法发生在依赖ViewModelProvider类内部androidx.lifecycle,当您查看类get()的函数时,就会发现这里的技巧,该函数ViewModelProvider检索您以前的ViewModel实例并将其与EmptyViewModel类进行比较,并且由于它们不一样,因此它运行mViewModelStore.put(key, viewModel);

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

        if (modelClass.isInstance(viewModel)) {
            //noinspection unchecked
            return (T) viewModel;
        } else {
            //noinspection StatementWithEmptyBody
            if (viewModel != null) {
                // TODO: log a warning.
            }
        }

        viewModel = mFactory.create(modelClass);
        mViewModelStore.put(key, viewModel);
        //noinspection unchecked
        return (T) viewModel;
    }
// ...
}
Run Code Online (Sandbox Code Playgroud)

如下所述,在依赖项ViewModelStore的类内部androidx.lifecycle,该put()方法将检索ShopViewModel并清除它,并替换EmptyViewModel实例。

public class ViewModelStore {
    //...
    final void put(String key, ViewModel viewModel) {
        ViewModel oldViewModel = mMap.put(key, viewModel);
        if (oldViewModel != null) {
            oldViewModel.onCleared();
        }
    }
    //...
}
Run Code Online (Sandbox Code Playgroud)