ViewModel 以注重生命周期的方式存储和管理界面相关的数据。 ViewModel 类让数据可在发生屏幕旋转等配置更改后继续留存。
问题: 1.旋转界面,配置更改,导致数据丢失,onSaveInstanceState() 方法保存 然后从 onCreate() 中的Bundle 或者 onRestoreInstanceState 恢复数据,但IPC对Bundle有1M的限制,如何做到大数据恢复
2.逻辑层会持有UI层的引用(比如:在MVP的Presenter中需要持有IView接口来回调结果给界面),如何避免内存泄漏
ViewModel生命周期长于Activity,因系统配置变更Activity销毁重建,ViewModel对象会保留并关联到新的Activity。而Activity的正常销毁(系统不会重建Activity)时,ViewModel对象是会清除的。
ViewModel包装了基于观察者模式的LiveData(问题2解决)
ViewModel使用: 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 class TestViewModelActivity : AppCompatActivity() { val TAG = "TestViewModelActivity" val myViewModel: MyViewModel by viewModels () override fun onCreate (savedInstanceState: Bundle?) { super .onCreate(savedInstanceState) setContentView(R.layout.activity_viewmodel) val name = findViewById<TextView>(R.id.name) Log.d(TAG, "myViewModel: $myViewModel" ) Log.d(TAG, "onCreate: / " + System.currentTimeMillis()) myViewModel.getUserData().observe(this , { Log.d(TAG, "observe:" + it.toString() + " / " + System.currentTimeMillis()) name.text = it.toString() }) } override fun onStart () { super .onStart() Log.d(TAG, "onStart: " ) } override fun onResume () { super .onResume() Log.d(TAG, "onResume: " ) } override fun onPause () { super .onPause() Log.d(TAG, "onPause: " ) } override fun onStop () { super .onStop() Log.d(TAG, "onStop: " ) } override fun onDestroy () { super .onDestroy() Log.d(TAG, "onDestroy: " ) } }
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 class MyViewModel : ViewModel() { private val userData: MutableLiveData<List<String>> by lazy { MutableLiveData<List<String>>().also { getData() } } private fun getData () { Thread { Thread.sleep(3000 ) userData.postValue(listOf("Stew" , "Helen" , "Bob" , "Lucy" )) Thread.sleep(3000 ) userData.postValue(listOf("Stew" , "Helen" , "Bob" )) }.start() } fun getUserData () : LiveData<List<String>> { return userData } }
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 TestViewModelActivity: myViewModel: com.stew.kotlinjetpack.viewmodel.MyViewModel@7ee52e8 TestViewModelActivity: onCreate: / 1658413519213 TestViewModelActivity: onStart: TestViewModelActivity: onResume: TestViewModelActivity: observe:[Stew, Helen, Bob, Lucy] / 1658413522218 TestViewModelActivity: observe:[Stew, Helen, Bob] / 1658413525219 旋转屏幕 TestViewModelActivity: onPause: TestViewModelActivity: onStop: TestViewModelActivity: onDestroy: TestViewModelActivity: myViewModel: com.stew.kotlinjetpack.viewmodel.MyViewModel@7ee52e8 TestViewModelActivity: onCreate: / 1658413576399 TestViewModelActivity: onStart: TestViewModelActivity: observe:[Stew, Helen, Bob] / 1658413576410 TestViewModelActivity: onResume:
如果在初始化的时候就开始获取数据,必须在子线程异步获取,不然会报错(?????)
旋转屏幕myViewModel不会变化,退出重进会变化
fragment共享viewmodel数据: 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 class Test4Fragment : Fragment() { private val sharedViewModel: SharedViewModel by activityViewModels () override fun onViewCreated (view: View, savedInstanceState: Bundle?) { super .onViewCreated(view, savedInstanceState) view.findViewById<TextView>(R.id.t1).setOnClickListener { i++ sharedViewModel.getData(i.toString()) } } } class Test5Fragment : Fragment() { val sharedViewModel: SharedViewModel by activityViewModels () override fun onViewCreated (view: View, savedInstanceState: Bundle?) { super .onViewCreated(view, savedInstanceState) val t = view.findViewById<TextView>(R.id.t1) sharedViewModel.getSharedData().observe(viewLifecycleOwner, { t.text = "Test5 data: $it" }) } }
源码分析 ViewModel实例的获取是通过ViewModelProvider类
ViewModelStoreOwner——ViewModel存储器拥有者; ViewModelStore——ViewModel存储器,用来存ViewModel的地方; Factory——创建ViewModel实例的工厂(通过传入的class 反射获取ViewModel实例。)
ViewModelStoreOwner是个接口,实现类有Activity/Fragment,也就是说 Activity/Fragment 都是 ViewModel存储器的拥有者
ViewModelStore中,viewModel作为Value存储在HashMap中。
viewModelProvider.get(UserViewModel.class) 先尝试从ViewModelStore获取ViewModel实例,如果没有获取到,就使用Factory创建,然后存入ViewModelStore。
ViewModelStoreOwner是个接口,实现类有Activity/Fragment
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 @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 ) { mViewModelStore = nc.viewModelStore; } if (mViewModelStore == null ) { mViewModelStore = new ViewModelStore (); } } return mViewModelStore; }
先尝试 从NonConfigurationInstance从获取 ViewModelStore实例,如果NonConfigurationInstance不存在,就new一个mViewModelStore。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 @Override @Nullable public final Object onRetainNonConfigurationInstance () { Object custom = onRetainCustomNonConfigurationInstance(); ViewModelStore viewModelStore = mViewModelStore; if (viewModelStore == null ) { NonConfigurationInstances nc = (NonConfigurationInstances) getLastNonConfigurationInstance(); if (nc != null ) { viewModelStore = nc.viewModelStore; } } if (viewModelStore == null && custom == null ) { return null ; } NonConfigurationInstances nci = new NonConfigurationInstances (); nci.custom = custom; nci.viewModelStore = viewModelStore; return nci; }
并且还注意到,在onRetainNonConfigurationInstance()方法中 会把mViewModelStore赋值给NonConfigurationInstances,在Activity因配置改变 而正要销毁时,且新Activity会立即创建,那么系统就会调用此方法,也就说,配置改变时 系统把viewModelStore存在了NonConfigurationInstances中。
ComponentActivity静态内部类,非配置实例
1 2 3 4 static final class NonConfigurationInstances { Object custom; ViewModelStore viewModelStore; }
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 NonConfigurationInstances mLastNonConfigurationInstances; public Object getLastNonConfigurationInstance () { return mLastNonConfigurationInstances != null ? mLastNonConfigurationInstances.activity : null ; } static final class NonConfigurationInstances { Object activity; HashMap<String, Object> children; FragmentManagerNonConfig fragments; ArrayMap<String, LoaderManager> loaders; VoiceInteractor voiceInteractor; } final void attach (Context context, ActivityThread aThread, ... NonConfigurationInstances lastNonConfigurationInstances,... ) { ... mLastNonConfigurationInstances = lastNonConfigurationInstances; ... }
mLastNonConfigurationInstances是在Activity的attach方法中赋值
lastNonConfigurationInstances是存在 ActivityClientRecord中的一个组件信息
ActivityThread 中的 ActivityClientRecord 是不受 activity 重建的影响,那么ActivityClientRecord中lastNonConfigurationInstances也不受影响,那么其中的Object activity也不受影响,那么ComponentActivity中的NonConfigurationInstances的viewModelStore不受影响,那么viewModel也就不受影响了。(问题1解决)
onSaveInstanceState的调用遵循一个重要原则,即当系统“未经你许可”时销毁了你的activity,则onSaveInstanceState会被系统调用
使用ViewModel恢复数据 则 只有在 因配置更改界面销毁重建 的情况。
ViewModel是存在内存中,读写速度快
onSaveInstanceState是序列化到磁盘中
ViewModel,可以存复杂数据,大小限制就是App的可用内存
onSaveInstanceState只能存可序列化和反序列化的对象,且大小有限制(一般Bundle限制大小1M)。