ViewModel
ViewModel是Android架构组件中负责管理UI数据与逻辑的,类似于MVP架构中的Persenter相似。
MVVM与MVP最大的区别就是使用viewmodel,即VM代替原来的P层。V层建议使用databinding实现,从而形成简洁高效的MVVM。
以感知生命周期的方式存储和管理视图相关的数据
(1)生命周期
旋转屏幕时activity会被销毁重新创建,而ViewModel却不会。它的生命周期
创建时传入了activity、Fragment对象实例(ViewModelProviders.of(this)
),所有它可以感知宿主的生命周期。
MainViewModel viewModel = ViewModelProviders.of(this).get(MainViewModel.class);
当宿主onDestory且非配置改变时,ViewModel便会自行销毁掉。
public ComponentActivity() { Lifecycle lifecycle = getLifecycle(); //noinspection ConstantConditions ··· 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(); } } } }); ···
(2)原理
@NonNull @MainThread public static ViewModelProvider of(@NonNull FragmentActivity activity, @Nullable Factory factory) { Application application = checkApplication(activity);//1 if (factory == null) { factory = ViewModelProvider.AndroidViewModelFactory.getInstance(application);//3 } return new ViewModelProvider(activity.getViewModelStore(), factory); }
通过ViewModelProvider.of()方法获取其对象,并传入factory工厂对象
@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)) { //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; }
调用ViewModelProvider.of().get()方法,通过工厂mFactoty创建ViewModel对象并返回
MyViewModel model = ViewModelProviders.of(this).get(MyViewModel.class);
小结:
- ViewModelStore是存储VM的数据单元,存储结构为Map,Fragment/FragmentActivity持有其引用。
- ViewModelProvider通过get方法创建一个VM,创建之前会先检查ViewModelStore中是否存在,若不存在则通过反射创建一个VM。
(3)UI组件间共享数据 Activity/Fragment如何共享数据
以下不能共享
### MainActivity override fun onCreate(savedInstanceState: Bundle?) { //传递activity val vm = ViewModelProviders.of(this).get(AndroidViewModel::class.java) } ### TestFragment override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) //传递fragment val vm = ViewModelProviders.of(this).get(AndroidViewModel::class.java) }
正确的写法应该是二者在of方法中传入相同的对象
### TestFragment.onCreate(savedInstanceState: Bundle?) //通过getActivity方法取得Fragment所在的Activity val vm = activity?.run { //run函数 这里的this指代activity ViewModelProviders.of(this)[AndroidViewModel::class.java] }
fragment之间共享数据同理,传入父activity或者parentFragment
(4)数据源更新UI
class NameViewModel : ViewModel() { private var mCurrentName: MutableLiveData<String>? = null fun getCurrentName() : MutableLiveData<String>?{ if (mCurrentName == null) { mCurrentName = MutableLiveData() } return mCurrentName } fun setCurrentName(name: String){ mCurrentName?.postValue(name) } }
class LiveDataActivity : AppCompatActivity() { private var mModel: NameViewModel? = null //视图绑定 private lateinit var binding: ActivityLivedataBinding override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) binding = ActivityLivedataBinding.inflate(layoutInflater) setContentView(binding.root) // setContentView(R.layout.activity_livedata) mModel = ViewModelProviders.of(this).get(NameViewModel::class.java) mModel!!.getCurrentName()?.observe(this, nameObserver) mModel!!.setCurrentName("sss") } }
private var nameObserver:Observer<String> = Observer {
binding.btn.text = it
}
不能直接更新mCurrentName数据源,否则观察者就会失效了。以下代码是无效的
fun setCurrentName(name:MutableLiveData<String>){ mCurrentName = name } mModel!!.setCurrentName(MutableLiveData("newText"))
(5)Activity发生配置变化时 数据如何保持
activity.ondestory 方法之前,会调用activitythread.performDestroyActivity方法,保存nonConfigurationInstance到ActivityRecord中
### ActivityThread performDestroyActivity(...boolean getNonConfigInstance,...) { ... if (getNonConfigInstance) { //如果配置发生改变记录下来 r.lastNonConfigurationInstances = r.activity.retainNonConfigurationInstances(); } }
activity重建时如何恢复数据? activity.attach
### Activity final void attach(Context context, ... NonConfigurationInstances lastNonConfigurationInstances,...) { ... mLastNonConfigurationInstances = lastNonConfigurationInstances; ... }
CompomentActivity.getViewModelStore() 方法里 通过nc获取数据 存储的viewModelStore
@NonNull @Override public ViewModelStore getViewModelStore() { 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(); if (nc != null) { // Restore the ViewModelStore from NonConfigurationInstances mViewModelStore = nc.viewModelStore; } if (mViewModelStore == null) { mViewModelStore = new ViewModelStore(); } } return mViewModelStore; }
(6)如何避免内存泄漏
view不持有context或者view的引用
参考:【背上Jetpack之ViewModel】即使您不使用MVVM也要了解ViewModel ——ViewModel 的职能边界 - 掘金 (juejin.cn)
Jetpack 系列(3)—— 为什么 Activity 都重建了 ViewModel 还存在? - 掘金 (juejin.cn)
ViewModel 结合LiveData使用案例
1、定义WifiViewModel
public class WifiViewModel extends ViewModel {
public static WifiViewModel INSTANCE=new WifiViewModel();
··· public MutableLiveData<AccessPoint>localAp;
public WifiViewModel(){ allNet=new MutableLiveData<>(); localAp=new MutableLiveData<>(); } ···
}
2、监听状态
//AP信息
mWifiViewModel.localAp.observeForever(localAp);
Observer<AccessPoint> localAp = new Observer<AccessPoint>() {
@Override
public void onChanged(AccessPoint accessPoint) {
if (accessPoint == null) {
return;
}
WifiController.this.localApAaccessPoint = accessPoint;
if (wifiApListener != null) {
wifiApListener.apConfigChanged(accessPoint);
}
}
};
3、修改数据
wifiViewModel.getLocalAp().setValue(getLocalAccessPoint());
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 10年+ .NET Coder 心语 ── 封装的思维:从隐藏、稳定开始理解其本质意义
· 地球OL攻略 —— 某应届生求职总结
· 周边上新:园子的第一款马克杯温暖上架
· Open-Sora 2.0 重磅开源!
· 提示词工程——AI应用必不可少的技术