ViewModel工作原理分析

解决问题:

  • ViewModel是什么?有什么作用?
  • ViewModel是如何做到页面生命周期发生变化(onDestory除外),数据保持不变的?
  • ViewModel工作原理及源码分析

1)ViewModel是什么?有什么作用?

ViewModel是什么:

ViewModel is a class that is responsible for preparing and managing the data for an {@link android.app.Activity Activity} or a {@link androidx.fragment.app.Fragment Fragment}.

  • ViewModel为页面提供并管理数据。
  • 专门用于存放应用程序页面所需的数据

ViewModel特点:

A ViewModel is always created in association with a scope (an fragment or an activity) and will be retained as long as the scope is alive. E.g. if it is an Activity, until it is finished.

In other words, this means that a ViewModel will not be destroyed if its owner is destroyed for a configuration change (e.g. rotation). The new instance of the owner will just re-connected to the existing ViewModel.

  • ViewModel在页面中创建,并独立与页面,实现数据与页面的分离;
  • 意味着屏幕旋转等配置所导致的Activity重建,并不会影响ViewModel的生命周期;

如下图所示:

  

 ViewModel的作用:

The purpose of the ViewModel is to acquire and keep the information that is necessary for an Activity or a Fragment. The Activity or the Fragment should be able to observe changes in the ViewModel.
  • 页面应当添加对ViewModel的观察
ViewModels usually expose this information via {@link LiveData} or Android Data Binding. You can also use any observability construct from you favorite framework.
  • ViewModel通过LiveData 或者 Android DataBinding 对外暴露数据
- 基本使用
 
 public class UserActivity extends Activity {
 
      {@literal @}Override
      protected void onCreate(Bundle savedInstanceState) {
          super.onCreate(savedInstanceState);
          setContentView(R.layout.user_activity_layout);
          final UserModel viewModel = new ViewModelProvider(this).get(UserModel.class);
          viewModel.getUser().observe(this, new Observer<User>() {
              {@literal @}Override
              public void onChanged(@Nullable User data) {
                  // update ui.
              }
          });
          findViewById(R.id.button).setOnClickListener(new View.OnClickListener() {
              {@literal @}Override
              public void onClick(View v) {
                   viewModel.doAction();
              }
          });
      }
  }

  public class UserModel extends ViewModel {
      private final MutableLiveData<User> userLiveData = new MutableLiveData<>();
 
      public LiveData<User> getUser() {
          return userLiveData;
      }
 
      public UserModel() {
          // trigger user load.
      }
 
      void doAction() {
          // depending on the action, do necessary business logic calls and update the
          // userLiveData.
      }
  }
ViewModel's only responsibility is to manage the data for the UI. It should never access your view hierarchy or hold a reference back to the Activity or the Fragment
  • ViewModel的作用就是为UI进行数据管理;
  • ViewModel决不能访问或持有页面或View的引用,以免内存泄露
ViewModels can also be used as a communication layer between different Fragments of an Activity. Each Fragment can acquire the ViewModel using the same key via their Activity. This allows communication between Fragments in a de-coupled(解耦) fashion such that they never need to talk to the other Fragment directly.
  • ViewModel可以用于在不同的页面间进行通信。每个页面通过同一个Key就可以获取ViewModel
  • 以一种解耦的方式进行相互间的通信
public class MyFragment extends Fragment {
    public void onStart() {
        UserModel userModel = new ViewModelProvider(requireActivity()).get(UserModel.class);
   }
}

2)ViewModel是如何做到页面生命周期发生变化(onDestory除外),数据保持不变的?

在ComponentActivity的构造方法中,有这么一段代码:

  •         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();// 清空Map缓存
                        }
                    }
                }
            });

仅在【页面销毁】且【非配置变化】的时候,清空ViewModel

3)原理分析

核心:

  • ViewModelStore(缓存当前页面的所有ViewModel)
  • ViewModelProvider(持有【当前页面】的ViewModel创建工厂及ViewModelStore)
  • NonConfigurationInstances

简言之:

  • ViewModelStore提供缓存ViewModel的能力
  • ViewModelProvider充当门面【获取、创建】
  • Restore the ViewModelStore from NonConfigurationInstances

ViewModelStore

原理很简单,就是一个Map缓存,Key就固定字符串+ViewModel的全路径名,Value是ViewModel实例:

public class ViewModelStore {

    private final HashMap<String, ViewModel> mMap = new HashMap<>();

    final void put(String key, ViewModel viewModel) {
        ViewModel oldViewModel = mMap.put(key, viewModel);
        if (oldViewModel != null) {
            oldViewModel.onCleared();
        }
    }

    final ViewModel get(String key) {
        return mMap.get(key);
    }

    Set<String> keys() {
        return new HashSet<>(mMap.keySet());
    }

    /**
     *  Clears internal storage and notifies ViewModels that they are no longer used.
     */
    public final void clear() {
        for (ViewModel vm : mMap.values()) {
            vm.clear();
        }
        mMap.clear();
    }
}

- ViewModelProvider。

官方注释:

An utility class that provides {@code ViewModels} for a scope.

为页面提供ViewModel的工具类。

基本用法:

MyViewModel mMyViewModel = new ViewModelProvider(this).get(MyViewModel.class);

- 源码层面:#1 -> #2 -> #3 -> #4
#1:
public static ViewModelProvider of(@NonNull FragmentActivity activity) {
    return new ViewModelProvider(activity);
}
#2:
public ViewModelProvider(@NonNull ViewModelStoreOwner owner) {
        this(owner.getViewModelStore(), owner instanceof HasDefaultViewModelProviderFactory
                ? ((HasDefaultViewModelProviderFactory) owner).getDefaultViewModelProviderFactory()
                : NewInstanceFactory.getInstance());
    }
#3:将ViewModel的创建工厂、ViewModelStore传递给ViewModelProvider 
  public ViewModelProvider(@NonNull ViewModelStoreOwner owner, @NonNull Factory factory) {
        this(owner.getViewModelStore(), factory);
    }
#4:
public ViewModelProvider(@NonNull ViewModelStore store, @NonNull Factory factory) {
        mFactory = factory;
        mViewModelStore = store;
    }

所以,可以Activity/Fragment都实现了ViewModelStoreOwner 接口,并返回自己的ViewModelStore:

- Activity

    public ViewModelStore getViewModelStore() {
        ......
        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;
    }
关于NonConfigurationInstances,在后面分析。

- Fragment

    public ViewModelStore getViewModelStore() {
        ......
        return mFragmentManager.getViewModelStore(this);
    }

简要源码分析:

// 为当前页面创建ViewModel
public class ViewModelProvider {

    private static final String DEFAULT_KEY =
            "androidx.lifecycle.ViewModelProvider.DefaultKey";

    // 创建ViewModel的工厂方法
    public interface Factory {
        // 反射创建
        @NonNull
        <T extends ViewModel> T create(@NonNull Class<T> modelClass);
    }

    private final Factory mFactory;// 创建工厂的实例
    private final ViewModelStore mViewModelStore;// 当前页面的ViewModelStore实例

    public <T extends ViewModel> T get(@NonNull Class<T> modelClass) {
        String canonicalName = modelClass.getCanonicalName();
        ......
        // Key的生成规则:
        return get(DEFAULT_KEY + ":" + canonicalName, modelClass);
    }

public <T extends ViewModel> T get(@NonNull String key, @NonNull Class<T> modelClass) 
{
        ViewModel viewModel = mViewModelStore.get(key);
        // 有则返回;
        if (modelClass.isInstance(viewModel)) {
            if (mFactory instanceof OnRequeryFactory) {
                ((OnRequeryFactory) mFactory).onRequery(viewModel);
            }
            return (T) viewModel;
        } else {
            //noinspection StatementWithEmptyBody
            if (viewModel != null) {
                // TODO: log a warning.
            }
        }
        // 无则创建;【反射创建,详见:AndroidViewModelFactory】
        if (mFactory instanceof KeyedFactory) {
            viewModel = ((KeyedFactory) (mFactory)).create(key, modelClass);
        } else {
            viewModel = (mFactory).create(modelClass);
        }
        // 保存在当前页面的ViewModelStore中
        mViewModelStore.put(key, viewModel);
        return (T) viewModel;
    }

ViewModelProvider就分析到这里。简言之:为当前页面的ViewModelStore生产ViewModel的。

- NonConfigurationInstances

Restore the ViewModelStore from NonConfigurationInstances

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值