首页 > 解决方案 > 如何使构造函数中带有 id 参数的 ViewModelFactory 可注入?

问题描述

我在带有 Dagger 的 Android 中使用 ViewModel 来管理依赖项。我的 ViewModel 将在创建时从 MainActivity 获取一个 id。所以我在这里有这些代码:

在活动中:

@inject ViewModelProviderFactory mViewModelFactory;
ViewModelProviders.of(this, mViewModelFactory).get(MyViewModel.class);

我的工厂供应商:

public class ViewModelProviderFactory implements ViewModelProvider.Factory {

    private int id;

    @inject
    public ViewModelProviderFactory(int id) {
        this.id = id;
    }

    @Override
    public <T extends ViewModel> T create(Class<T> modelClass) {
        return new MyViewModel(id);
    }    
}

为了工作,我需要向我的模块添加一个参数:

@Module
public class MainActivityModule {
    int id;
    public MainActivityModule(int id){ 
        this.id = id;
    }
    @Provides
    ViewModelProvider.Factory mainViewModelProvider() {
        return new ViewModelProviderFactory<>(id);
    }
}

或者我可以直接在组件中做它并使其抽象。在新的 Dagger 中,我可以使用 Dagger 类来制作活动或片段组件。因此,我应该为每个活动创建子组件,并为我应该编写的其他代码创建一个 Builder 和音调。

是否有任何简单和更好的方法来防止这些额外的代码,或者我最好通过在这样的活动中调用一个新工厂来创建我的工厂?:

ViewModelProviders.of(this, new ViewModelProviderFactory(id)).get(MyViewModel.class);

标签: androiddaggerandroid-viewmodel

解决方案


new ViewModelProviderFactory(id)在我看来,从那里调用Activity是更简单的解决方案。但是,我不会直接Activity. 相反,我会创建工厂(是的,工厂的工厂......),我会注入Activity.

这是一个例子:

class FactoryOfFactory {

    @Inject
    FactoryOfFactory() {}

    ViewModelProvider.Factory create(int id) {
        // ViewModelProviderFactory can now by just an anonymous class
        return new ViewModelProvider.Factory() {
            @Override
            public <T extends ViewModel> T create(Class<T> modelClass) {
                return (T) new MyViewModel(id);
            }
        };
    }
}

以及用法:

class ClientActivity extends AppCompatActivity {

    @Inject
    FactoryOfFactory factoryOfFactory;

    @Override
    protected void onCreate(@Nullable final Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);

        final int id = 123;
        ViewModelProviders.of(this, factoryOfFactory.create(id)).get(MyViewModel.class);
    }
}

该方法也有如下解决方案:如果MyViewModel需要其他依赖(不提供Activity),我们可以很容易地添加它们(无需修改Activity):

class MyViewModel extends ViewModel {
    MyViewModel(int id, AnotherDependency anotherDependency) { }
}

class FactoryOfFactory {

    private final AnotherDependency anotherDependency; // added

    @Inject
    FactoryOfFactory(final AnotherDependency anotherDependency) {  // modified
        this.anotherDependency = anotherDependency; // added
    }

    ViewModelProvider.Factory create(int id) {
        // ViewModelProviderFactory can now by just an anonymous class
        return new ViewModelProvider.Factory() {
            @Override
            public <T extends ViewModel> T create(Class<T> modelClass) {
                return (T) new MyViewModel(id, anotherDependency);  // modified
            }
        };
    }
}

而且,当然,我相信一个比FactoryOfFactory存在更好的名字;)


推荐阅读