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

Android配置变更时ViewModel重复调用构造函数原因排查

Let's break down exactly what's happening here, and yes—your dependency injection setup is the root cause of this behavior.

The Core Issue: Your DI is bypassing ViewModel's lifecycle management

By default, ViewModelProvider is designed to retain ViewModels across configuration changes (like screen rotations). It only creates a new ViewModel instance if one doesn't already exist for the given lifecycle owner (your Activity/Fragment). But your current DI setup forces a new ViewModel instance to be created every time you retrieve the ViewModelProvider.Factory, which breaks this retention.

Let's look at your DI code specifically:

@Provides
ViewModelProvider.Factory mainViewModelProvider(MainViewModel mainViewModel) {
    return new ViewModelProviderFactory<>(mainViewModel);
}

When your DI framework resolves this ViewModelProvider.Factory, it first has to create a new MainViewModel instance to pass into the factory. This happens every time your Activity is recreated (on rotation), because performInjection() runs in onCreate().

So instead of letting ViewModelProvider decide when to create the ViewModel, your DI is pre-creating a new instance on every Activity/Fragment rebuild—and the factory just hands that pre-made instance over. This completely skips the ViewModel's retention mechanism.

Why your Fragment's BalanceViewModel is also recreating

Your Fragment's code uses the same flawed pattern:

@Override public BalanceViewModel setViewModel() {
    return ViewModelProviders.of(this, viewModelFactory).get(BalanceViewModel.class);
}

If your viewModelFactory for BalanceViewModel is set up the same way as your MainViewModel's factory (pre-creating the ViewModel instance), then every time the Fragment is recreated (on rotation), DI will spin up a new BalanceViewModel, and the old one will be cleared (hence the onCleared() log entry).

How to fix this

You need to adjust your DI setup to let ViewModelProvider control when ViewModels are created, instead of pre-instantiating them. Here are two common approaches:

1. Use a ViewModel-specific Factory class

Create a nested Factory class inside your ViewModel that handles instantiation, and inject its dependencies:

// Inside MainViewModel.java
public class MainViewModel extends ViewModel {
    private final SomeDependency dependency;

    public MainViewModel(SomeDependency dependency) {
        this.dependency = dependency;
    }

    @Inject
    public static class Factory extends ViewModelProvider.NewInstanceFactory {
        private final SomeDependency dependency;

        @Inject
        public Factory(SomeDependency dependency) {
            this.dependency = dependency;
        }

        @Override
        public <T extends ViewModel> T create(Class<T> modelClass) {
            if (modelClass.isAssignableFrom(MainViewModel.class)) {
                return (T) new MainViewModel(dependency);
            }
            throw new IllegalArgumentException("Unknown ViewModel class: " + modelClass);
        }
    }
}

Then update your DI module to provide this Factory instead of pre-creating the ViewModel:

@Provides
ViewModelProvider.Factory mainViewModelProvider(MainViewModel.Factory factory) {
    return factory;
}

This way, the Factory only creates a new MainViewModel when ViewModelProvider calls create()—which only happens if there's no existing instance for the lifecycle owner.

2. Use a generic ViewModel Factory (scalable for multiple ViewModels)

For apps with many ViewModels, a generic factory that uses a map of ViewModel classes to their DI providers is more efficient:

public class GenericViewModelFactory implements ViewModelProvider.Factory {
    private final Map<Class<? extends ViewModel>, Provider<ViewModel>> viewModelProviders;

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

    @Override
    @SuppressWarnings("unchecked")
    public <T extends ViewModel> T create(Class<T> modelClass) {
        Provider<? extends ViewModel> provider = viewModelProviders.get(modelClass);
        if (provider == null) {
            // Fallback for subclass ViewModels
            for (Map.Entry<Class<? extends ViewModel>, Provider<ViewModel>> entry : viewModelProviders.entrySet()) {
                if (modelClass.isAssignableFrom(entry.getKey())) {
                    provider = entry.getValue();
                    break;
                }
            }
        }
        if (provider == null) {
            throw new IllegalArgumentException("No provider found for ViewModel class: " + modelClass);
        }
        try {
            return (T) provider.get();
        } catch (Exception e) {
            throw new RuntimeException("Failed to create ViewModel", e);
        }
    }
}

Then bind your ViewModels to this factory using DI's @IntoMap and a custom @ViewModelKey:

// Define a ViewModelKey annotation
@MapKey
@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
public @interface ViewModelKey {
    Class<? extends ViewModel> value();
}

// In your DI module
@Binds
@IntoMap
@ViewModelKey(MainViewModel.class)
abstract ViewModel bindMainViewModel(MainViewModel viewModel);

@Binds
@IntoMap
@ViewModelKey(BalanceViewModel.class)
abstract ViewModel bindBalanceViewModel(BalanceViewModel viewModel);

@Binds
abstract ViewModelProvider.Factory bindViewModelFactory(GenericViewModelFactory factory);

This setup lets your DI framework handle mapping ViewModel classes to their providers, and the generic factory only retrieves a new instance when ViewModelProvider requests it—preserving the ViewModel's lifecycle retention.

Summary

Your ViewModels are recreating on rotation because your DI configuration is pre-instantiating ViewModels and passing them into the factory, instead of letting ViewModelProvider manage when instances are created. Fixing your DI setup to defer ViewModel creation to the factory will resolve the issue and restore the expected ViewModel lifecycle behavior.

内容的提问来源于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:17:16