ViewModel

SavedStateViewModel(ViewModel + onSaveInstanceState)

ViewModel 可以在配置更改时保存状态;onSaveInstanceState 可以在内存不足进程被杀死时保存状态,onCreate 方法的 Bundle 参数可能为空,如果在 onCreate 方法里恢复数据,一定要做非空判断

onSaveInstanceState 调用时机

  • 启动新的 Activity,导致原 Activity 被盖住时
  • 默认情况下横竖屏切换时
  • 手机息屏时
  • 当用户按下手机 home 键时
  • 长按手机home键或者按下菜单键时

各种 Android 系统操作都会影响 Fragment 的状态,为了确保用户的状态得到保存,Android 框架会自动保存和恢复 Fragment 和返回堆栈

// FragmentActivity
final FragmentController mFragments = 
                  FragmentController.createController(new HostCallbacks());
addOnContextAvailableListener(new OnContextAvailableListener() {
    @Override
    public void onContextAvailable(@NonNull Context context) {
        mFragments.attachHost(null /*parent*/);
        Bundle savedInstanceState = getSavedStateRegistry()
            .consumeRestoredStateForKey(FRAGMENTS_TAG);

        if (savedInstanceState != null) {
            Parcelable p = savedInstanceState.getParcelable(FRAGMENTS_TAG);
            mFragments.restoreSaveState(p);
        }
    }
});

// FragmentController
public void restoreSaveState(@Nullable Parcelable state) {
    mHost.mFragmentManager.restoreSaveState(state);
}

// FragmentManager
fragmentStateManager = new FragmentStateManager(mLifecycleCallbacksDispatcher,
                             mFragmentStore, mHost.getContext().getClassLoader(),
                             getFragmentFactory(), fs);

// FragmentStateManager
FragmentStateManager(FragmentLifecycleCallbacksDispatcher dispatcher,
                     FragmentStore fragmentStore, ClassLoader classLoader,
                     FragmentFactory fragmentFactory, FragmentState fs) {
    mDispatcher = dispatcher;
    mFragmentStore = fragmentStore;
    mFragment = fragmentFactory.instantiate(classLoader, fs.mClassName);
    if (fs.mArguments != null) {
        fs.mArguments.setClassLoader(classLoader);
    }
    mFragment.setArguments(fs.mArguments);
    if (fs.mSavedFragmentState != null) {
        mFragment.mSavedFragmentState = fs.mSavedFragmentState;
    } else {
        mFragment.mSavedFragmentState = new Bundle();
    }
}

// 在 Fragment 中恢复自定义的 SavedState
void activityCreated() {
    if (FragmentManager.isLoggingEnabled(Log.DEBUG)) {
        Log.d(TAG, "moveto ACTIVITY_CREATED: " + mFragment);
    }
    mFragment.performActivityCreated(mFragment.mSavedFragmentState);
    mDispatcher.dispatchOnFragmentActivityCreated(
        mFragment, mFragment.mSavedFragmentState, false);
}

Android 框架提供的所有视图都有自己的 onSaveInstanceState 和 onRestoreInstanceState 实现,因此您不必管理 Fragment 中的视图状态。视图需要一个 ID 才能保留其状态,此 ID 在 Fragment 及其视图层次结构中必须是唯一的,没有 ID 的视图无法保留其状态

onSaveInstanceState 数据存储位置和大小限制

onSaveInstanceState 中保存的 Bundle 数据最终会通过 IActivityManager 保存在系统内存中,由于需要通过 Binder 进行通讯,而 Binder 传输缓冲区有 1M 大小的限制,所以 onSaveInstanceState 也有相同的限制

ViewModel 原理

  1. 不会因配置改变而销毁
  2. 用于管理 UI 界面数据,将加载数据与数据恢复从 Activity / Fragment中解耦
  3. 多个 Fragment 可以共享同一 ViewModel
  4. 配合 LiveData,可感知生命周期

通过 Fragment.setRetainedFragment 或 Activity.onSaveNonConfigurationInstance 保存的数据都可以在配置改变时不销毁

关键类:ViewModelProvider(辅助工具类)、 ViewModelStore(通过 Key 保存了不同的 ViewModel)

在宿主 Activity 创建时,默认会在其 FramgentManager 中创建一个 FragmentManagerViewModel。同时将生成的 FragmentManagerViewModel 存储在其本身的 ViewModelStore 中,同时使用自身的 FragmentManager 的名称作为 Key 值

子 Fragment 通过 getFragmentManager 持有父 FragmentManager,自身的 ViewModelStore 保存自己的 ViewModel,并存入父 FragmentManagerViewModel 的 mViewModelStores 中,自身的 FragmentManagerViewModel 存入父 FragmentManagerViewModel 的 mChildNonConfigs中

FragmentManagerViewModel.png

<think>好的,我现在要回答用户关于ViewModelMVVM架构中的作用及实现方式的问题。首先,我需要回忆一下MVVM的基本结构。根据引用中的信息,MVVM分为Model、View和ViewModel三层。ViewModel的作用是连接View和Model,处理业务逻辑,并且保持数据状态,这样即使View层(如Activity或Fragment)因配置改变而重建,数据也不会丢失。 接下来,我需要明确ViewModel的具体职责。根据引用[2]和[4],ViewModel负责预处理数据,使其适合UI显示,并通过LiveData等可观察对象通知View更新。此外,ViewModel应避免持有View的引用,以防止内存泄漏,这符合引用[4]提到的分离逻辑。 关于实现方式,用户提到使用Kotlin和Android组件,比如LiveData和ViewModel。引用[2]和[5]中的代码示例展示了如何创建ViewModel类,并利用LiveData来管理数据。例如,在Kotlin中,ViewModel通常与Repository(数据仓库)交互,处理数据获取和业务逻辑,然后通过LiveData将数据暴露给View层。 另外,数据绑定(Data Binding)也是一个关键点,引用[3]指出MVVM适用于数据绑定,这可以减少View层的胶水代码,使UI更新自动化。需要提到如何在布局文件中绑定ViewModel的数据,以及如何通过双向绑定处理用户输入。 还要注意ViewModel的生命周期,它比关联的View(如Activity)生命周期更长,因此可以管理配置变化时的数据持久化。引用[4]提到ViewModel的创建和与View的交互方式,应使用ViewModelProvider来获取实例,确保正确的作用域。 可能还需要对比其他架构,比如MVC和MVP,突出MVVM的优势,如关注点分离、可测试性和维护性。引用[3]提到MVVMMVC的变体,特别适合处理复杂的UI逻辑和数据绑定。 最后,根据用户提供的引用,特别是引用[2]和[4],需要总结ViewModel的实现步骤:定义ViewModel类,使用LiveData暴露数据,在View层观察这些数据,并通过Data Binding或手动更新UI。同时,确保Model层处理数据源,ViewModel作为中间层协调数据流动。 可能还需要检查是否有遗漏的要点,比如依赖注入(如使用Hilt或Koin)来管理ViewModel的依赖关系,或者如何处理网络请求和数据库操作与ViewModel的交互。引用[5]中的代码示例显示ViewModel可能持有Repository实例,负责调用其方法获取数据。 总结时,要明确ViewModel的核心作用,即解耦视图逻辑与业务逻辑,管理数据状态,并通过观察者模式实现数据驱动UI。实现方式包括正确的组件使用(LiveData、ViewModel)、遵循生命周期感知,以及合理的数据绑定策略。</think>### ViewModelMVVM 架构中的作用及实现方式 #### 1. ViewModel 的核心作用 - **数据与 UI 解耦**:ViewModel 作为 Model 和 View 的中间层,负责将原始数据转换为适合 UI 显示的形式(例如格式化字符串、过滤列表等)[^2][^4]。 - **状态管理**:保存与界面相关的数据状态(如用户输入、页面配置),即使 View 因屏幕旋转等配置变化被重建,数据也不会丢失[^4]。 - **业务逻辑封装**:处理用户交互触发的操作(如按钮点击、网络请求),避免在 View 层编写复杂逻辑[^4]。 - **数据观察机制**:通过 `LiveData`、`Flow` 或 `State` 等可观察对象,向 View 层提供数据更新通知,实现数据驱动 UI。 #### 2. ViewModel 的实现方式(以 Android 为例) **步骤 1:定义 ViewModel 类** 继承 `ViewModel` 或 `AndroidViewModel`,并持有数据仓库(Repository)的引用: ```kotlin class UserViewModel(private val userRepository: UserRepository) : ViewModel() { private val _userData = MutableLiveData<User>() val userData: LiveData<User> = _userData fun loadUser(userId: String) { viewModelScope.launch { _userData.value = userRepository.fetchUser(userId) } } } ``` **步骤 2:在 View 层绑定 ViewModel** 通过 `ViewModelProvider` 获取 ViewModel 实例,并观察数据变化: ```kotlin class UserActivity : AppCompatActivity() { private lateinit var viewModel: UserViewModel override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) viewModel = ViewModelProvider(this).get(UserViewModel::class.java) viewModel.userData.observe(this) { user -> // 更新 UI,例如显示用户名称 textView.text = user.name } viewModel.loadUser("123") } } ``` **步骤 3:结合数据绑定(可选)** 在布局文件中直接绑定 ViewModel 的数据,减少手动更新 UI 的代码: ```xml <layout> <data> <variable name="viewModel" type="com.example.UserViewModel" /> </data> <TextView android:text="@{viewModel.userData.name}" ... /> </layout> ``` #### 3. 关键注意事项 - **生命周期感知**:ViewModel 的生命周期与关联的 Activity/Fragment 独立,避免内存泄漏。 - **依赖注入**:推荐通过依赖注入框架(如 Hilt)管理 ViewModel 的依赖(如 Repository)[^5]。 - **单元测试**:ViewModel 不依赖 Android 框架,便于单独测试业务逻辑。 ---
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

little-sparrow

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值