9、JetPack之ViewModel

1、介绍

ViewModel是一个为view(Activity\Fragment)准备数据和管理数据的类,是业务逻辑类

可以看到ViewModel不会被销毁,除非view层不存在了,才会清除掉

2、ViewModel的创建

定义OnSellViewMode类继承抽象类ViewModel,这里viewModel层相当于逻辑层,处理相关业务逻辑代码,且不持有view层的引用

class OnSellViewModel : ViewModel() {
    companion object {
        private const val TAG = "OnSellViewModel"

        // 默认为第一页
        const val DEFAULT_PAGE = 1
    }

    // 观察的数据对象
    val mContentList = MutableLiveData<MutableList<OnSellBean.TbkDgOptimusMaterialResponse.ResultList.MapData>>()

    // 观察的页面加载状态
    val mLoadState = MutableLiveData<LoadState>()

    // 当前页
    private var mCurrentPage = DEFAULT_PAGE

    private val mOnSellRepository by lazy {
        OnSellRepository()
    }

    private var mIsLoadMore = false

    /**
     * 加载首页内容
     */
    fun loadContent() {
        mIsLoadMore = false
        // 将页面状态置为Loading
        mLoadState.value = LoadState.LOADING
        this.listContentByPage(mCurrentPage)
    }

    private fun listContentByPage(page: Int) {
        // 使用挂起的方式
        viewModelScope.launch {
            try {
                // 请求数据成功
                val onSellList = mOnSellRepository.getOnSellList(page)
                val oldValue = mContentList.value?: mutableListOf()
                oldValue.addAll(onSellList.tbk_dg_optimus_material_response.result_list.map_data)
                Log.d(TAG, "cfx listContentByPage 请求数据成功")
                if (onSellList.tbk_dg_optimus_material_response.result_list.map_data.isNotEmpty()) {
                    Log.d(TAG, "cfx onSellList " + onSellList.tbk_dg_optimus_material_response.result_list.map_data.size)
                    // 设置数据
                    mContentList.value = oldValue
                    // 将页面状态置为SUCCESS
                    mLoadState.value = LoadState.SUCCESS
                } else {
                    Log.d(TAG, "cfx listContentByPage 请求数据成功 数据内容为空")
                    // 将页面状态置为EMPTY
                    mLoadState.value = if (mIsLoadMore) LoadState.LOAD_MORE_EMPTY else LoadState.EMPTY
                }
            } catch (e: Exception) {
                mCurrentPage--
                // 请求数据失败
                mLoadState.value = if (mIsLoadMore) LoadState.LOAD_MORE_ERROR else LoadState.NETWORK_ERROR
                Log.d(TAG, "cfx listContentByPage 请求数据失败 e: $e")
            }
        }
    }

    /**
     * 上拉加载更多
     */
    fun loadMore() {
        mIsLoadMore = true
        mLoadState.value = LoadState.LOAD_MORE_LOADING
        Log.d(TAG, "cfx loadMore")
        // 去加载更多内容
        mCurrentPage++
        this.listContentByPage(mCurrentPage)
    }
}

在view层通过ViewModelProvider创建viewModel实例,处理相关业务即可

 3、ViewModel创建方式源码分析

通过ViewModelProvider(this).get获取到viewModel实例对象,这里的this指的是owner,那么owner又是什么呢?

可以看到,这个owner是实现了ViewModelStoreOwner接口的对象,那么既然可以传入this,view层一定实现了该接口

 可以看到,在ComponentActivity中实现了ViewModelStoreOwner接口,所以可以直接传入this

 再进一步看看这个接口的作用是什么?可以发现这个接口和LifecycleOwner类似,只是为了获取到

ViewModelStore,我们再看看ViewModelStore的作用吧

 可以发现,ViewModelStore就是一个map集合,根据key,存储对应的ViewModel,并提供了增删查改的方法,这样view层就有了这个mViewModelStore对象来管理ViewModel

/**
 * Class to store {@code ViewModels}.
 * <p>
 * An instance of {@code ViewModelStore} must be retained through configuration changes:
 * if an owner of this {@code ViewModelStore} is destroyed and recreated due to configuration
 * changes, new instance of an owner should still have the same old instance of
 * {@code ViewModelStore}.
 * <p>
 * If an owner of this {@code ViewModelStore} is destroyed and is not going to be recreated,
 * then it should call {@link #clear()} on this {@code ViewModelStore}, so {@code ViewModels} would
 * be notified that they are no longer used.
 * <p>
 * Use {@link ViewModelStoreOwner#getViewModelStore()} to retrieve a {@code ViewModelStore} for
 * activities and fragments.
 */
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的构造方法中去,通过owner获取到viewModelStore对象,并赋值给成员属性,然后调用get方法

 通过get方法,便获取到了viewModel对象

这里多次创建返回的是同一个ViewMNodel对象,并不会创建多个对象,因为view没有发生变化,这个this就不会发生变化,因此获取到的mViewModelStore就是同一个集合对象,因此取出来的ViewModel对象也是同一个,例如一个Activity中的多个Fragment中都创建了ViewModel,会使用宿主Activity的this作为ViewModelOwner来创建Viewmodel, 因此是同一个对象

4、ViewModel如何和View的生命周期挂钩

 

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值