IT数码 购物 网址 头条 软件 日历 阅读 图书馆
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
图片批量下载器
↓批量下载图片,美女图库↓
图片自动播放器
↓图片自动播放器↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁
 
   -> 移动开发 -> ViewModel使用到源码解读 -> 正文阅读

[移动开发]ViewModel使用到源码解读

介绍

ViewModel 是一个类,负责为 Activity 或 Fragment 准备和管理数据。它还处理 Activity Fragment 与应用程序其余部分的通信(例如调用业务逻辑类)。 ViewModel 始终与范围(片段或活动)关联创建,并且只要范围处于活动状态就会保留。例如。如果它是一个活动,直到它完成。换句话说,这意味着如果 ViewModel 的所有者因配置更改(例如旋转)而被销毁,则不会销毁 ViewModel。新的所有者实例只是重新连接到现有模型。 ViewModel 的目的是获取和保存 Activity 或 Fragment 所需的信息。 Activity 或 Fragment 应该能够观察到 ViewModel 的变化。 ViewModel 通常通过 LiveData 或 Android 数据绑定公开这些信息。您还可以使用您喜欢的框架中的任何可观察性构造。 ViewModel 的唯一职责是管理 UI 的数据。它永远不应访问您的视图层次结构或保留对 Activity 或 Fragment 的引用。

使用

class MainActivity : AppCompatActivity() {

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_main)

        val textView = findViewById<TextView>(R.id.text1)

        val viewModelProvider = ViewModelProvider(this)
        val mainViewModel = viewModelProvider.get(MainViewModel::class.java)
        mainViewModel.stringMutableLiveData.observe(this) {
            Log.e(TAG, "onCreate: 收到数据...")
            textView.text = Gson().toJson(it)
        }

        findViewById<View>(R.id.btn).setOnClickListener {
            Log.e(TAG, "onCreate: 发出网络请求...")
            mainViewModel.getWeChatPublicAccount()
        }
    }
}
public class MainViewModel extends ViewModel {

    private MutableLiveData<WeChatPublicAccountBean> stringMutableLiveData = new MutableLiveData<>();

    public MutableLiveData<WeChatPublicAccountBean> getStringMutableLiveData() {
        return stringMutableLiveData;
    }

    public void getWeChatPublicAccount() {
        NetworkManager.INSTANCE.create(WanAndroidApi.class)
                .getWeChatPublicAccount()
                .compose(RxUtil.io2main())
                .subscribe(new SimpleObserver<WeChatPublicAccountBean>() {
                    @Override
                    public void oNext(WeChatPublicAccountBean weChatPublicAccountBean, Disposable disposable) {
                        stringMutableLiveData.setValue(weChatPublicAccountBean);
                    }
                });
    }
}

运行效果

这是进入界面点击了一下按钮打印的日志

?

?接下来横竖屏切换一下

?

?从上面日志上可以看到只有最开始点击按钮发了网络请求,横竖屏切换后直接在LiveData#observer中就收到了数据(LiveData下篇文章讲解),接下里我们从源码上看一下ViewModel的实现

构造

    public ViewModelProvider(@NonNull ViewModelStoreOwner owner) {
        this(owner.getViewModelStore(), owner instanceof HasDefaultViewModelProviderFactory
                ? ((HasDefaultViewModelProviderFactory) owner).getDefaultViewModelProviderFactory()
                : NewInstanceFactory.getInstance());
    }

    public ViewModelProvider(@NonNull ViewModelStoreOwner owner, @NonNull Factory factory) {
        this(owner.getViewModelStore(), factory);
    }

    public ViewModelProvider(@NonNull ViewModelStore store, @NonNull Factory factory) {
        mFactory = factory;
        mViewModelStore = store;
    }

构造上发现创建ViewModel对象需要ViewModelStore,Factory在我们的demo中使用的是单参数构造我们继续看到owner#getViewModelStore的调用

ComponentActivity#getViewModelStore

    public ViewModelStore getViewModelStore() {
        if (mViewModelStore == null) {
            //注释1
            NonConfigurationInstances nc =
                    (NonConfigurationInstances) getLastNonConfigurationInstance();
            if (nc != null) {
                mViewModelStore = nc.viewModelStore;
            }
            //注释2
            if (mViewModelStore == null) {
                mViewModelStore = new ViewModelStore();
            }
        }
        return mViewModelStore;
    }

我们构造时传入的是this,也就是当前MainActivity对象,MainActivity的间接父类ComponentActivity就实现了ViewModelStoreOwner接口所有owner#getViewModelStore调用到的就是我们上面贴出的这段源码

上面源码中可以看到单个的Activity对象只会有一个ViewModelStore对象,我们先看到注释1,这里尝试获取一个NonConfigurationInstances对象但正常情况下这个对象是为null的,只有在我们进行了横竖屏切换时这个对象才是存在的我们继续看下对这个对象是如何进行保存的

? ? / ** Called by the system, as part of destroying an
? ? ? activity due to a configuration change, when it is known that a new
? ? ? instance will immediately be created for the new configuration. ?You
? ? ? can return any object you like here, including the activity instance
? ? ? itself, which can later be retrieved by calling
? ? ? {@link #getLastNonConfigurationInstance()} in the new activity
? ? ? instance. **/



       public final Object onRetainNonConfigurationInstance() {
        // Maintain backward compatibility.
        Object custom = onRetainCustomNonConfigurationInstance();

        ViewModelStore viewModelStore = mViewModelStore;
        if (viewModelStore == null) {
            // No one called getViewModelStore(), so see if there was an existing
            // ViewModelStore from our last NonConfigurationInstance
            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在横竖屏切换时会由系统调用我们可以在这里保存一些数据,并且我们可以调用getLastNonConfigurationInstance获得之前保存的对象,ViewModel就是通过这个函数保存了我们之前的ViewModelStore对象,就是说不管横竖屏切换多少次我们每次获取的ViewModel对象都是同一个,这就是ViewModel横竖屏切换不需要重新请求数据的秘密了

接下来是ViewModelProvider构造的第二个参数ViewModelProvider#Factory

因为ComponentActivity中同样实现了HasDefaultViewModelProviderFactory接口所有我们继续看到ComponentActivity#HasDefaultViewModelProviderFactory源码

ComponentActivity#HasDefaultViewModelProviderFactory

    public ViewModelProvider.Factory getDefaultViewModelProviderFactory() {
        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 (mDefaultFactory == null) {
            mDefaultFactory = new SavedStateViewModelFactory(
                    getApplication(),
                    this,
                    getIntent() != null ? getIntent().getExtras() : null);
        }
        return mDefaultFactory;
    }

这里没啥好说的就是返回了一个SavedStateViewModelFactory对象

我在再往下看viewModelProvider是如何获取对应ViewModel的

viewModelProvider#get

    public <T extends ViewModel> T get(@NonNull Class<T> modelClass) {
        String canonicalName = modelClass.getCanonicalName();
        if (canonicalName == null) {
            throw new IllegalArgumentException("Local and anonymous classes can not be ViewModels");
        }
        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.
            }
        }
        if (mFactory instanceof KeyedFactory) {
            viewModel = ((KeyedFactory) mFactory).create(key, modelClass);
        } else {
            viewModel = mFactory.create(modelClass);
        }
        mViewModelStore.put(key, viewModel);
        return (T) viewModel;
    }

这里的代码就相对简单了就是如果在原先的ViewModelStore中存在对应class的ViewModel就直接返回,没有则用Factory进行创建并保存到ViewModelStore中下次就可以直接获取不用再次新建了

  移动开发 最新文章
Vue3装载axios和element-ui
android adb cmd
【xcode】Xcode常用快捷键与技巧
Android开发中的线程池使用
Java 和 Android 的 Base64
Android 测试文字编码格式
微信小程序支付
安卓权限记录
知乎之自动养号
【Android Jetpack】DataStore
上一篇文章      下一篇文章      查看所有文章
加:2022-02-28 15:41:20  更:2022-02-28 15:41:22 
 
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁

360图书馆 购物 三丰科技 阅读网 日历 万年历 2024年11日历 -2024/11/24 15:46:53-

图片自动播放器
↓图片自动播放器↓
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
图片批量下载器
↓批量下载图片,美女图库↓
  网站联系: qq:121756557 email:121756557@qq.com  IT数码