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);

小结:

  1. ViewModelStore是存储VM的数据单元,存储结构为Map,Fragment/FragmentActivity持有其引用。
  2. 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());

 

posted @ 2022-12-27 17:11  随易来了  阅读(147)  评论(0编辑  收藏  举报