加强党建网站建设的重要性佛山百度快照优化排名
The ViewModel class is a business logic or screen level state holder.
上面是官方给的定义,ViewModel 类是业务逻辑或屏幕级状态持有者。
一、业务逻辑持有者
在此之前,无论是MVC模式,还是MVP模式,在视图层,都会产生对业务逻辑层的依赖,从而导致出现内存泄漏的情况。那ViewModel又是如何处理业务逻辑层和视图层的依赖,从而避免了常见的内存泄漏的问题的呢?
依赖Lifecycle对宿主生命周期的感知,处理对Viewmodel的依赖
1.1、应用
NormalViewModel
package com.anniljing.viewmodelcorestudy;import android.app.Application;import java.util.ArrayList;
import java.util.List;import androidx.annotation.NonNull;
import androidx.lifecycle.AndroidViewModel;public class NormalViewModel extends AndroidViewModel {public NormalViewModel(@NonNull Application application) {super(application);}public List<Integer> getdatas() {List<Integer> data = new ArrayList<>();for (int i = 0; i < 10; i++) {data.add(i);}return data;}
}
NormalActivity
package com.anniljing.viewmodelcorestudy;import android.os.Bundle;import com.anniljing.viewmodelcorestudy.databinding.ActivityNormalBinding;import androidx.appcompat.app.AppCompatActivity;
import androidx.lifecycle.ViewModelProvider;public class NormalActivity extends AppCompatActivity {private ActivityNormalBinding mBinding;private NormalViewModel mViewModel;@Overrideprotected void onCreate(Bundle savedInstanceState) {super.onCreate(savedInstanceState);mBinding = ActivityNormalBinding.inflate(getLayoutInflater());setContentView(mBinding.getRoot());mViewModel = new ViewModelProvider(this).get(NormalViewModel.class);}
}
ComponentActivity源码
getLifecycle().addObserver(new LifecycleEventObserver() {@Overridepublic void onStateChanged(@NonNull LifecycleOwner source,@NonNull Lifecycle.Event event) {if (event == Lifecycle.Event.ON_DESTROY) {// Clear out the available contextmContextAwareHelper.clearAvailableContext();// And clear the ViewModelStoreif (!isChangingConfigurations()) {getViewModelStore().clear();}}}});
此处在Activity中Lifecycle的ON_DESTROY事件中,清除了ViewModel。
1.2、源码解析
1.2.1 创建ViewModelStore
public ComponentActivity() {Lifecycle lifecycle = getLifecycle();//noinspection ConstantConditionsif (lifecycle == null) {throw new IllegalStateException("getLifecycle() returned null in ComponentActivity's "+ "constructor. Please make sure you are lazily constructing your Lifecycle "+ "in the first call to getLifecycle() rather than relying on field "+ "initialization.");}getLifecycle().addObserver(new LifecycleEventObserver() {@Overridepublic void onStateChanged(@NonNull LifecycleOwner source,@NonNull Lifecycle.Event event) {if (event == Lifecycle.Event.ON_DESTROY) {// Clear out the available contextmContextAwareHelper.clearAvailableContext();// And clear the ViewModelStoreif (!isChangingConfigurations()) {getViewModelStore().clear();}}}});getLifecycle().addObserver(new LifecycleEventObserver() {@Overridepublic void onStateChanged(@NonNull LifecycleOwner source,@NonNull Lifecycle.Event event) {ensureViewModelStore();getLifecycle().removeObserver(this);}});}
在ComponentActivity的构造方法中,注册了多个Lifecycle的观察者,其中有两个涉及ViewModelStore的,一个是收到宿主的生命周期事件后,就创建了ViewModelStore,随后就移除了该观察者;另一个则是监听到宿主的ON_DESTROY事件后,清空ViewModelStore的ViewModel
1.2.2、创建Factory
1.2.2.1、创建ViewModel的时候,第一步我们创建了ViewModelProvider,调用了其中一个构造方法
public constructor(owner: ViewModelStoreOwner) : this(owner.viewModelStore, defaultFactory(owner), defaultCreationExtras(owner))
1.2.2.2、ViewModelProvider的构造方法中,调用了默认的Factory
public companion object {internal fun defaultFactory(owner: ViewModelStoreOwner): Factory =if (owner is HasDefaultViewModelProviderFactory)owner.defaultViewModelProviderFactory else instanceinternal const val DEFAULT_KEY = "androidx.lifecycle.ViewModelProvider.DefaultKey"}
1.2.2.3、由于ComponentActivity实现了HasDefaultViewModelProviderFactory接口,所以Factory的实际对象是SavedStateViewModelFactory
@NonNull@Overridepublic ViewModelProvider.Factory getDefaultViewModelProviderFactory() {if (mDefaultFactory == null) {mDefaultFactory = new SavedStateViewModelFactory(getApplication(),this,getIntent() != null ? getIntent().getExtras() : null);}return mDefaultFactory;}
1.2.3、创建ViewModel
public open operator fun <T : ViewModel> get(key: String, modelClass: Class<T>): T {val viewModel = store[key]if (modelClass.isInstance(viewModel)) {(factory as? OnRequeryFactory)?.onRequery(viewModel)return viewModel as T} else {@Suppress("ControlFlowWithEmptyBody")if (viewModel != null) {// TODO: log a warning.}}val extras = MutableCreationExtras(defaultCreationExtras)extras[VIEW_MODEL_KEY] = key// AGP has some desugaring issues associated with compileOnly dependencies so we need to// fall back to the other create method to keep from crashing.return try {factory.create(modelClass, extras)} catch (e: AbstractMethodError) {factory.create(modelClass)}.also { store.put(key, it) }}
应用层通过ViewModelProvider的get方法创建ViewModel,并且保存到ViewModelStore中。
二、屏幕状态的持有者
该功能主要处理当设备配置发生变化时,界面会重新绘制,导致数据丢失的问题。
屏幕发生旋转的时候,会调用onDestroy方法,界面会重新绘制。
2.1、ViewModel之前
2.1.1、manifest中配置
在activity里面的configChanges属性里面配置orientation|screenSize,则屏幕旋转的时候,界面就不会重新绘制。
2.1.2、onSaveInstanceState和onRestoreInstanceState
如果manifest里面没有配置configChanges,则屏幕旋转的时候,在onDestroy之前会调用onSaveInstanceState,在恢复界面的时候,会调用onRestoreInstanceState,这样我们就可以在以上两个方法中做保存和恢复数据的逻辑。
package com.anniljing.viewmodelcorestudy;import android.os.Bundle;
import android.util.Log;import com.anniljing.viewmodelcorestudy.databinding.ActivitySaveStateBinding;import androidx.annotation.NonNull;
import androidx.appcompat.app.AppCompatActivity;public class SaveStateActivity extends AppCompatActivity {private static final String TAG = "SaveStateActivity";private ActivitySaveStateBinding mBinding;private NormalState mNormalState;private static final String KEY="NormalState";private String saveString="";@Overrideprotected void onCreate(Bundle savedInstanceState) {super.onCreate(savedInstanceState);Log.e(TAG, "onCreate");if (savedInstanceState !=null){saveString=savedInstanceState.getString(KEY,"");}mBinding = ActivitySaveStateBinding.inflate(getLayoutInflater());setContentView(mBinding.getRoot());mNormalState = new NormalState();mNormalState.setString(saveString);Log.e(TAG, mNormalState.getString());mBinding.tvState.setOnClickListener((view) -> {mNormalState.setString("NormalState");Log.e(TAG,"Click after:"+ mNormalState.getString());});}@Overrideprotected void onSaveInstanceState(@NonNull Bundle outState) {super.onSaveInstanceState(outState);Log.e(TAG, "onSaveInstanceState");outState.putString(KEY,"NormalState");}@Overrideprotected void onRestoreInstanceState(@NonNull Bundle savedInstanceState) {super.onRestoreInstanceState(savedInstanceState);Log.e(TAG, "onRestoreInstanceState");}@Overrideprotected void onDestroy() {super.onDestroy();Log.e(TAG, "onDestroy");}
}
保存数据:
重新绘制的时候,取出数据:
在onSaveInstanceState里面增加保存逻辑,在onCreate方法里面就可以恢复以前的数据了。
2.2、 使用ViewModel
ViewModelSaveState:
package com.anniljing.viewmodelcorestudy;import android.app.Application;import androidx.annotation.NonNull;
import androidx.lifecycle.AndroidViewModel;public class ViewModelSaveState extends AndroidViewModel {private String mString;public ViewModelSaveState(@NonNull Application application) {super(application);}public String getString() {return mString;}public void setString(String string) {mString = string;}
}
package com.anniljing.viewmodelcorestudy;import android.os.Bundle;
import android.util.Log;import com.anniljing.viewmodelcorestudy.databinding.ActivitySaveStateBinding;import androidx.appcompat.app.AppCompatActivity;
import androidx.lifecycle.ViewModelProvider;public class SaveStateActivity extends AppCompatActivity {private static final String TAG = "SaveStateActivity";private ActivitySaveStateBinding mBinding;private ViewModelSaveState mViewModelSaveState;@Overrideprotected void onCreate(Bundle savedInstanceState) {super.onCreate(savedInstanceState);Log.e(TAG, "onCreate");mBinding = ActivitySaveStateBinding.inflate(getLayoutInflater());setContentView(mBinding.getRoot());mViewModelSaveState = new ViewModelProvider(this).get(ViewModelSaveState.class);Log.e(TAG,"Before click:"+mViewModelSaveState.getString());mBinding.tvState.setOnClickListener((view) -> {mViewModelSaveState.setString("ViewModelState");Log.e(TAG, "Click after:" + mViewModelSaveState.getString());});}@Overrideprotected void onDestroy() {super.onDestroy();Log.e(TAG,"onDestroy");}
}
可以看到,引入ViewModel以后,不需要在onSaveInstanceState方法中增加额外的保存逻辑,重绘后就可以恢复以前的数据。
无论是ViewModel,还是重写onSaveInstanceState方法,当内存有限导致界面退出重绘时,就无法恢复以前的数据了。
我们可以通过以下操作来模拟内存不足时,导致应用杀死的效果:
1、启用开发者模式
2、打开“不保留活动”
3、打开应用后,按home键,退出应用
4、重新打开应用。
2.3、使用SavedStateHandle
ViewModelWithHandleSaveState
package com.anniljing.viewmodelcorestudy;import androidx.lifecycle.MutableLiveData;
import androidx.lifecycle.SavedStateHandle;
import androidx.lifecycle.ViewModel;public class ViewModelWithHandleSaveState extends ViewModel {private static final String KEY = "ViewModelWithHandleSaveState";private SavedStateHandle mStateHandle;public ViewModelWithHandleSaveState(SavedStateHandle stateHandle) {mStateHandle = stateHandle;}public MutableLiveData<String> getLiveData() {return mStateHandle.getLiveData(KEY);}
}
1、构造方法里面添加SavedStateHandle参数。
2、获取的时候通过mStateHandle。
SaveStateActivity
package com.anniljing.viewmodelcorestudy;import android.os.Bundle;
import android.util.Log;import com.anniljing.viewmodelcorestudy.databinding.ActivitySaveStateBinding;import androidx.appcompat.app.AppCompatActivity;
import androidx.lifecycle.ViewModelProvider;public class SaveStateActivity extends AppCompatActivity {private static final String TAG = "SaveStateActivity";private ActivitySaveStateBinding mBinding;private ViewModelWithHandleSaveState mWithHandleSaveState;@Overrideprotected void onCreate(Bundle savedInstanceState) {super.onCreate(savedInstanceState);Log.e(TAG, "onCreate");mBinding = ActivitySaveStateBinding.inflate(getLayoutInflater());setContentView(mBinding.getRoot());mWithHandleSaveState = new ViewModelProvider(this).get(ViewModelWithHandleSaveState.class);Log.e(TAG, "Before click:" + mWithHandleSaveState.getLiveData().getValue());mWithHandleSaveState.getLiveData().observe(this, s -> {Log.e(TAG, "After click:" + mWithHandleSaveState.getLiveData().getValue());});mBinding.tvState.setOnClickListener((view) -> mWithHandleSaveState.getLiveData().postValue("ViewModelWithHandleSaveState"));}@Overrideprotected void onDestroy() {super.onDestroy();Log.e(TAG, "onDestroy");}
}