java.lang.RuntimeException:无法在

问题描述 投票:0回答:2

我正在开发食谱 Android 应用程序并使用 koin 依赖注入,但是当我运行该项目时,我收到以下异常]

java.lang.RuntimeException: Cannot create an instance of class com.example.cookpadapp.viewmodel.CookpadViewModel
        at androidx.lifecycle.ViewModelProvider$NewInstanceFactory.create(ViewModelProvider.kt:188)
        at androidx.lifecycle.ViewModelProvider$AndroidViewModelFactory.create(ViewModelProvider.kt:238)
        at androidx.lifecycle.SavedStateViewModelFactory.create(SavedStateViewModelFactory.java:113)
        at androidx.lifecycle.ViewModelProvider.get(ViewModelProvider.kt:169)
        at androidx.lifecycle.ViewModelProvider.get(ViewModelProvider.kt:139)
        at androidx.lifecycle.ViewModelLazy.getValue(ViewModelLazy.kt:44)
        at androidx.lifecycle.ViewModelLazy.getValue(ViewModelLazy.kt:31)
        at com.example.cookpadapp.CookpadFragment.getViewModel(CookpadFragment.kt:21)
        at com.example.cookpadapp.CookpadFragment.initObservers(CookpadFragment.kt:41)
        at com.example.cookpadapp.CookpadFragment.onViewCreated(CookpadFragment.kt:30)
        at androidx.fragment.app.Fragment.performViewCreated(Fragment.java:2987)
        at androidx.fragment.app.FragmentStateManager.createView(FragmentStateManager.java:546)
        at androidx.fragment.app.FragmentStateManager.moveToExpectedState(FragmentStateManager.java:282)
        at androidx.fragment.app.FragmentStore.moveToExpectedState(FragmentStore.java:112)
        at androidx.fragment.app.FragmentManager.moveToState(FragmentManager.java:1647)
        at androidx.fragment.app.FragmentManager.dispatchStateChange(FragmentManager.java:3128)
        at androidx.fragment.app.FragmentManager.dispatchViewCreated(FragmentManager.java:3065)
        at androidx.fragment.app.Fragment.performViewCreated(Fragment.java:2988)
        at androidx.fragment.app.FragmentStateManager.createView(FragmentStateManager.java:546)
        at androidx.fragment.app.FragmentStateManager.moveToExpectedState(FragmentStateManager.java:282)
        at androidx.fragment.app.FragmentStore.moveToExpectedState(FragmentStore.java:112)
        at androidx.fragment.app.FragmentManager.moveToState(FragmentManager.java:1647)
        at androidx.fragment.app.FragmentManager.dispatchStateChange(FragmentManager.java:3128)
        at androidx.fragment.app.FragmentManager.dispatchActivityCreated(FragmentManager.java:3072)
        at androidx.fragment.app.FragmentController.dispatchActivityCreated(FragmentController.java:251)
        at androidx.fragment.app.FragmentActivity.onStart(FragmentActivity.java:502)
        at androidx.appcompat.app.AppCompatActivity.onStart(AppCompatActivity.java:246)
        at android.app.Instrumentation.callActivityOnStart(Instrumentation.java:1392)
        at android.app.Activity.performStart(Activity.java:7252)
        at android.app.ActivityThread.handleStartActivity(ActivityThread.java:3000)
        at android.app.servertransaction.TransactionExecutor.performLifecycleSequence(TransactionExecutor.java:185)
        at android.app.servertransaction.TransactionExecutor.cycleToPath(TransactionExecutor.java:170)
        at android.app.servertransaction.TransactionExecutor.executeLifecycleState(TransactionExecutor.java:147)
        at android.app.servertransaction.TransactionExecutor.execute(TransactionExecutor.java:73)
        at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1858)
        at android.os.Handler.dispatchMessage(Handler.java:106)
        at android.os.Looper.loop(Looper.java:201)
        at android.app.ActivityThread.main(ActivityThread.java:6820)
        at java.lang.reflect.Method.invoke(Native Method)
        at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:547)
        at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:922)
     Caused by: java.lang.InstantiationException: java.lang.Class<com.example.cookpadapp.viewmodel.CookpadViewModel> has no zero argument constructor
        at java.lang.Class.newInstance(Native Method)

在我的 CookpadViewModel.kt 下方

import androidx.lifecycle.MutableLiveData
import androidx.lifecycle.ViewModel
import androidx.lifecycle.viewModelScope
import com.example.cookpadapp.domain.use_case.GetRecipeUseCase
import com.example.cookpadapp.domain.utils.fold
import com.example.cookpadapp.model.Recipe
import com.example.cookpadapp.model.RecipeResponse
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.launch

class CookpadViewModel(private val recipeUseCase: GetRecipeUseCase) : ViewModel() {

    var cookpad = MutableLiveData<RecipeResponse>()

    // Expose to the outside world
    val error = MutableLiveData<String>()
    var progress = MutableLiveData(false)


    init {
        getRecipes()
    }

    fun getRecipes() {
        progress.postValue(true)
        viewModelScope.launch(Dispatchers.IO) {
            recipeUseCase.invoke()
                .fold({  recipeResponse->
                    cookpad.postValue(recipeResponse)
                }, {
                   error.postValue(it.message)
                })
            progress.postValue(false)
        }
    }

    fun onRecipeClicked(recipe: Recipe) {

  

} }

在我的 CookpadFragment.kt 下方

package com.example.cookpadapp

import android.os.BaseBundle
import android.os.Bundle
import androidx.fragment.app.Fragment
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import androidx.fragment.app.viewModels
import com.example.cookpadapp.databinding.FragmentCookpadBinding
import com.example.cookpadapp.ui.BaseFragment
import com.example.cookpadapp.ui.adapter.RecipeAdapter
import com.example.cookpadapp.viewmodel.CookpadViewModel
import org.koin.androidx.viewmodel.ext.android.viewModel

// TODO: item_recipe, RecipeAdapter, fragment_cookpad
class CookpadFragment : BaseFragment<FragmentCookpadBinding>() {

    override val layoutId: Int = R.layout.fragment_cookpad

    private val viewModel: CookpadViewModel by viewModels()

    private val adapter = RecipeAdapter(arrayListOf()) { recipe ->
        viewModel.onRecipeClicked(recipe)
    }

    override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
        super.onViewCreated(view, savedInstanceState)
        initViews()
        initObservers()
    }

    private fun initViews() {
        binding.recipeRV.adapter = adapter
        binding.swipeRefresh.setOnRefreshListener {
            viewModel.getRecipes()
        }
    }

    private fun initObservers() {
        viewModel.cookpad.observe(viewLifecycleOwner) { recipes ->
            adapter.update(recipes)
        }
        viewModel.progress.observe(viewLifecycleOwner) { loading ->
            binding.swipeRefresh.isRefreshing = loading
        }
    }
}

在我的 Modules.kt 下面,我实现了 koin 逻辑

object Modules {

    val viewModels = module {
        viewModel { CookpadViewModel(get()) }
        viewModel{DetailCookpadViewModel(get())}
    }

    val apiModule = module {

        factory { CookpadRepository(get()) }
        factory { GetRecipeUseCase(get()) }
        factory { GetRecipeDetailsUseCase(get()) }


        single<CookpadInterface> {
            provideRetrofit(get<OkHttpClient>())
        }

        factory<OkHttpClient> {
            provideOkHttpClient(get<Cache>())
        }

        factory<Cache> {
            provideCache(get<Context>())
        }
    }
}


fun provideCache(context: Context): Cache {
    val cacheSize: Long = 10 * 1024 * 1024
    return Cache(context.cacheDir, cacheSize)
}

fun provideOkHttpClient(cache: Cache): OkHttpClient {
    val logger = HttpLoggingInterceptor().apply {
        level = HttpLoggingInterceptor.Level.BODY
    }

    return OkHttpClient.Builder()
        .connectTimeout(60, TimeUnit.SECONDS)
        .writeTimeout(60, TimeUnit.SECONDS)
        .readTimeout(60, TimeUnit.SECONDS)
        .cache(cache)
        .addInterceptor(logger)
        .build()
}

fun provideRetrofit(okHttpClient: OkHttpClient): CookpadInterface {
    return Retrofit.Builder()
        .baseUrl(Constants.BASE_URL)
        .client(okHttpClient)
        .addConverterFactory(GsonConverterFactory.create())
        .addCallAdapterFactory(CoroutineCallAdapterFactory.invoke())
        .build()
        .create(CookpadInterface::class.java)
}

在 GetRecipeUseCase.kt 下方

class GetRecipeUseCase(
    private val cookpadRepository: CookpadRepository
) {

    suspend operator fun invoke() = cookpadRepository.getRecipes()
}

我想知道我到底在哪里犯了错误,我遵循了所有 stackoverflow 答案,但它没有解决我的问题

android kotlin viewmodel koin
2个回答
0
投票

我通过在 CookpadFragment 中导入并添加以下方式解决了我的问题

private val viewModel: CookpadViewModel by viewModel()
import org.koin.androidx.viewmodel.ext.android.viewModel

0
投票

如果您使用 Hilt,您可能会忘记添加@AndroidEntryPoint,如下所示:

@AndroidEntryPoint
class CreateIssueActivity : ComponentActivity() {

}
© www.soinside.com 2019 - 2024. All rights reserved.