【问题标题】:how to inject viewModel into a fragment - dagger 2如何将 viewModel 注入片段 - 匕首 2
【发布时间】:2021-08-20 19:39:00
【问题描述】:

您好,我正在使用 dagger 2 进行依赖注入,当我尝试在我的片段中注入 MainActivityViewModel 时,我收到错误 lateinit property viewModelx has not been initialized

这些是相关的依赖文件和Fragment

复古模块

@Module
class RetroModule {

    @Singleton
    @Provides
    fun getRetrofitInstance(): Retrofit {
        return Retrofit.Builder()
            .baseUrl(baseURL)
            .addConverterFactory(GsonConverterFactory.create())
            .build()
    }

    @Singleton
    @Provides
    fun getApiService(): ApiServiceInterface =
        getRetrofitInstance().create(ApiServiceInterface::class.java)

    companion object {
        private val baseURL = "https://android-interview.s3.eu-west-2.amazonaws.com/"
    }
}

复古组件

@Singleton
@Component(modules = [RetroModule::class])
interface RetroComponent {

    fun inject(mainActivityViewModel: MainActivityViewModel)
}

片段

class CreditScoreFragment : Fragment() {

    @Inject lateinit var viewModelx: MainActivityViewModel

    override fun onCreateView(
        inflater: LayoutInflater, container: ViewGroup?,
        savedInstanceState: Bundle?
    ): View {
        _binding = FragmentCreditScoreBinding.inflate(inflater, container, false)
        val view = binding.root
        initViewModel()
        initView()
        return view
    }

    private fun initViewModel() {
        viewModelx.getCreditReportObserver().observe(viewLifecycleOwner, Observer<CreditReport> {
            showScoreUI(true)
            binding.score.text = it.creditReportInfo.score.toString()
            binding.maxScoreValue.text = "out of ${it.creditReportInfo.maxScoreValue}"
            initDonutView(
                it.creditReportInfo.score.toFloat(),
                it.creditReportInfo.maxScoreValue.toFloat()
            )
        })
        viewModelx.getServerErrorLiveDataObserver().observe(viewLifecycleOwner, Observer<Boolean> {
            if(it) {
                showScoreUI(false)
                showToastMessage()
            }
        })
        viewModelx.getCreditReport()
    }

 companion object {
        @JvmStatic
        fun newInstance() =
            CreditScoreFragment().apply {}
    }

}

错误更新

xxx/app/build/tmp/kapt3/stubs/debug/com/example/clearscore/di/ViewModelModule.java:18: error: @Binds methods' parameter type must be assignable to the return type
    public abstract androidx.lifecycle.ViewModelProvider.Factory bindMainActivityViewModel_Factory(@org.jetbrains.annotations.NotNull()
                                                                 ^xxx/app/build/tmp/kapt3/stubs/debug/com/example/clearscore/di/RetroComponent.java:18: error: @Component.Factory abstract methods must return the @Component type or a supertype of the @Component. Inherited method: create(T)
    public static abstract class Factory implements dagger.android.AndroidInjector.Factory<com.example.clearscore.MyApplication> {
                           ^xxxapp/build/tmp/kapt3/stubs/debug/com/example/clearscore/di/RetroComponent.java:6: error: com.example.clearscore.di.ViewModelModule has errors
@dagger.Component(modules = {com.example.clearscore.di.RetroModule.class, com.example.clearscore.di.ViewModelModule.class})

视图模型模块

@Module
abstract class ViewModelModule {

    @Binds
    @IntoMap
    @ViewModelKey(MainActivityViewModel::class )
    // Bind your View Model here
    abstract fun bindMainActivityViewModel(viewModel: MainActivityViewModel): ViewModel

    @Binds
    // Bind viewModelFactory if you have custom ViewModelFactory
    abstract fun bindMainActivityViewModel_Factory(factory: MainActivityViewModel_Factory): ViewModelProvider.Factory
}

MainActivityViewModel_Factory

@DaggerGenerated
@SuppressWarnings({
    "unchecked",
    "rawtypes"
})
public final class MainActivityViewModel_Factory implements Factory<MainActivityViewModel> {
  private final Provider<DataRepository> dataRepositoryProvider;

  public MainActivityViewModel_Factory(Provider<DataRepository> dataRepositoryProvider) {
    this.dataRepositoryProvider = dataRepositoryProvider;
  }

  @Override
  public MainActivityViewModel get() {
    return newInstance(dataRepositoryProvider.get());
  }

  public static MainActivityViewModel_Factory create(
      Provider<DataRepository> dataRepositoryProvider) {
    return new MainActivityViewModel_Factory(dataRepositoryProvider);
  }

  public static MainActivityViewModel newInstance(DataRepository dataRepository) {
    return new MainActivityViewModel(dataRepository);
  }
}

【问题讨论】:

    标签: android kotlin dependency-injection dagger-2


    【解决方案1】:

    您需要在视图模型模块中声明提供者:

    @Binds
    @IntoMap
    @ViewModelKey(MainActivityViewModel::class)
    abstract fun provideMainActivityViewModel(viewModel: MainActivityViewModel): ViewModel
    

    你的 Fragment 也必须在你的模块中声明:

    @FragmentScope
    @ContributesAndroidInjector
    abstract fun provideCreditScoreFragment(): CreditScoreFragment
    

    在您的片段中,当您声明视图模型时,有必要对其进行初始化,例如使用延迟初始化,如您所愿:

     private val viewModel: MainActivityViewModel by lazy {
            ViewModelProvider(this, yourViewModelFactory).get(MainActivityViewModel::class.java)
     }
    

    最后你可以在片段中注入你的视图模型工厂(记得在模块中声明工厂)

    【讨论】:

      【解决方案2】:

      我认为你错过了什么。根据您何时开始使用您的依赖项,在 onAttach 或 onCreate 中添加 AndroidSupportInjection.inject(this) 这将有助于 dagger 注入。

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 2015-11-04
        • 1970-01-01
        • 1970-01-01
        • 2017-11-29
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多