You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Android屏幕旋转时MainViewModel重复创建问题咨询

看起来你遇到了ViewModel在配置变化时重复创建的问题,我来帮你分析一下原因和对应的解决方案:

问题原因分析

从你的代码和日志来看,每次旋转手机触发配置变化时MainViewModel的构造函数都会被调用,这和官方文档中ViewModel会在配置变化时保留实例的描述不符,问题大概率出在这几个地方:

1. ViewModelFactory的实现存在问题

你的MainViewModel用@Inject标记构造函数,说明依赖Dagger创建实例。如果你的ViewModelFactory实现逻辑有问题——比如每次调用create()方法都会返回新的MainViewModel,或者没有正确复用Dagger提供的作用域实例——就会导致ViewModelProviders.get()每次都创建新对象。

2. BaseActivity的ViewModel赋值逻辑有漏洞

在BaseActivity的performDataBinding()方法里:

this.viewModel = viewModel == null ? onCreateViewModel() : viewModel;

当Activity旋转重建时,成员变量viewModel会被重置为null,所以每次都会触发onCreateViewModel()。虽然ViewModelProviders.of(this).get()理论上应该返回已有的实例,但如果ViewModelStore中的实例被意外清空,就会触发Factory创建新实例。

3. ViewModelStoreOwner不正确

如果你的BaseActivity直接继承自原生Activity,而不是AppCompatActivity或FragmentActivity,它就没有实现ViewModelStoreOwner接口,ViewModelProviders.of(this)无法获取正确的ViewModelStore,自然无法保留旧实例。

4. Lifecycle依赖库版本过低

旧版本的Android Lifecycle库可能存在配置变化时ViewModel无法保留的bug,这也会导致重复创建的问题。


解决方案

步骤1:检查并修复ViewModelFactory实现

确保你的ViewModelFactory正确实现ViewModelProvider.Factory,并且通过Dagger作用域复用ViewModel实例。标准的Dagger ViewModelFactory实现应该是这样的:

@Singleton
public class ViewModelFactory implements ViewModelProvider.Factory {
    private final Map<Class<? extends ViewModel>, Provider<ViewModel>> creators;

    @Inject
    public ViewModelFactory(Map<Class<? extends ViewModel>, Provider<ViewModel>> creators) {
        this.creators = creators;
    }

    @SuppressWarnings("unchecked")
    @Override
    public <T extends ViewModel> T create(Class<T> modelClass) {
        Provider<? extends ViewModel> creator = creators.get(modelClass);
        if (creator == null) {
            for (Map.Entry<Class<? extends ViewModel>, Provider<ViewModel>> entry : creators.entrySet()) {
                if (modelClass.isAssignableFrom(entry.getKey())) {
                    creator = entry.getValue();
                    break;
                }
            }
        }
        if (creator == null) {
            throw new IllegalArgumentException("Unknown ViewModel class: " + modelClass);
        }
        try {
            return (T) creator.get();
        } catch (Exception e) {
            throw new RuntimeException(e);
        }
    }
}

同时给MainViewModel添加@ActivityScope(或对应作用域),确保Dagger在Activity生命周期内复用该实例。

步骤2:修改BaseActivity的ViewModel获取逻辑

去掉成员变量的null检查,直接调用onCreateViewModel()——因为ViewModelProviders.get()本身会自动复用已有的实例,无需手动判断:

private void performDataBinding() {
    viewDataBinding = DataBindingUtil.setContentView(this, setLayoutId());
    // 直接获取ViewModel,ViewModelProviders会自动返回已有的实例
    this.viewModel = onCreateViewModel();
    viewDataBinding.setVariable(setBindingVariable(), viewModel);
    viewDataBinding.executePendingBindings();
}

步骤3:确认BaseActivity的父类

确保BaseActivity继承自AppCompatActivity或FragmentActivity,这些类已经实现了ViewModelStoreOwner接口,能正确管理ViewModelStore:

public abstract class BaseActivity extends AppCompatActivity {
    // ... 你的其他代码
}

步骤4:升级Lifecycle依赖库

在build.gradle中升级到最新的Lifecycle稳定版本(比如2.6.1):

dependencies {
    implementation "androidx.lifecycle:lifecycle-viewmodel:2.6.1"
    implementation "androidx.lifecycle:lifecycle-livedata:2.6.1"
    implementation "androidx.lifecycle:lifecycle-runtime:2.6.1"
}

步骤5:排查ViewModelStore是否被意外清空

检查你的代码中是否有调用ViewModelStore.clear()的逻辑(比如在onDestroy()方法中),这会直接清空ViewModel实例,导致每次重建都要创建新对象。


按照以上步骤排查后,应该就能解决旋转手机时ViewModel重复创建的问题了。

内容的提问来源于stack exchange,提问作者Ivan Sablin

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.29 08:25:49