私はフラグメントクラスでViewModelを使ってKOINを実装していますが、エミュレータのコードをテストすると、次のエラーが発生しています。
Java.lang.RuntimeException: Java.lang.reflect.InvocationTargetException
at com.Android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.Java:557)
at com.Android.internal.os.ZygoteInit.main(ZygoteInit.Java:922)
Caused by: Java.lang.reflect.InvocationTargetException
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: org.koin.core.error.InstanceCreationException: Could not create instance for [type:Factory,primary_type:'yodgorbek.komilov.musobaqayangiliklari.viewmodel.MainViewModel']
at org.koin.core.instance.DefinitionInstance.create(DefinitionInstance.kt:61)
at org.koin.core.instance.FactoryDefinitionInstance.get(FactoryDefinitionInstance.kt:37)
at org.koin.core.definition.BeanDefinition.resolveInstance(BeanDefinition.kt:70)
at org.koin.core.scope.Scope.resolveInstance(Scope.kt:165)
at org.koin.core.scope.Scope.get(Scope.kt:128)
at org.koin.androidx.viewmodel.ViewModelResolutionKt$createViewModelProvider$1.create(ViewModelResolution.kt:66)
at androidx.lifecycle.ViewModelProvider.get(ViewModelProvider.Java:164)
at androidx.lifecycle.ViewModelProvider.get(ViewModelProvider.Java:130)
at org.koin.androidx.viewmodel.ViewModelResolutionKt.getInstance(ViewModelResolution.kt:43)
at org.koin.androidx.viewmodel.ViewModelResolutionKt.getViewModel(ViewModelResolution.kt:23)
at org.koin.androidx.viewmodel.ext.Android.LifecycleOwnerExtKt.getViewModel(LifecycleOwnerExt.kt:85)
at yodgorbek.komilov.musobaqayangiliklari.ui.TopHeadlinesFragment$$special$$inlined$viewModel$1.invoke(LifecycleOwnerExt.kt:95)
at yodgorbek.komilov.musobaqayangiliklari.ui.TopHeadlinesFragment$$special$$inlined$viewModel$1.invoke(Unknown Source:0)
at kotlin.SynchronizedLazyImpl.getValue(LazyJVM.kt:74)
at yodgorbek.komilov.musobaqayangiliklari.ui.TopHeadlinesFragment.getViewModel(Unknown Source:7)
at yodgorbek.komilov.musobaqayangiliklari.ui.TopHeadlinesFragment.initViewModel(TopHeadlinesFragment.kt:57)
at yodgorbek.komilov.musobaqayangiliklari.ui.TopHeadlinesFragment.onCreateView(TopHeadlinesFragment.kt:51)
at androidx.fragment.app.Fragment.performCreateView(Fragment.Java:2600)
at androidx.fragment.app.FragmentManagerImpl.moveToState(FragmentManagerImpl.Java:881)
at androidx.fragment.app.FragmentManagerImpl.moveFragmentToExpectedState(FragmentManagerImpl.Java:1238)
at androidx.fragment.app.FragmentManagerImpl.moveToState(FragmentManagerImpl.Java:1303)
at androidx.fragment.app.BackStackRecord.executeOps(BackStackRecord.Java:439)
at androidx.fragment.app.FragmentManagerImpl.executeOps(FragmentManagerImpl.Java:2079)
at androidx.fragment.app.FragmentManagerImpl.executeOpsTogether(FragmentManagerImpl.Java:1869)
at androidx.fragment.app.FragmentManagerImpl.removeRedundantOperationsAndExecute(FragmentManagerImpl.Java:1824)
at androidx.fragment.app.FragmentManagerImpl.execPendingActions(FragmentManagerImpl.Java:1727)
at androidx.fragment.app.FragmentManagerImpl.dispatchStateChange(FragmentManagerImpl.Java:2663)
at androidx.fragment.app.FragmentManagerImpl.dispatchActivityCreated(FragmentManagerImpl.Java:2613)
at androidx.fragment.app.FragmentController.dispatchActivityCreated(FragmentController.Java:246)
at androidx.fragment.app.FragmentActivity.onStart(FragmentActivity.Java:542)
at androidx.appcompat.app.AppCompatActivity.onStart(AppCompatActivity.Java:201)
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)
2019-11-16 15:12:01.728 12995-12995/yodgorbek.komilov.musobaqayangiliklari E/AndroidRuntime: 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)
... 3 more
Caused by: org.koin.core.error.NoBeanDefFoundException: No definition found for 'Java.lang.Object' has been found. Check your module definitions.
at org.koin.core.scope.Scope.findDefinition(Scope.kt:170)
at org.koin.core.scope.Scope.resolveInstance(Scope.kt:164)
at org.koin.core.scope.Scope.get(Scope.kt:128)
at yodgorbek.komilov.musobaqayangiliklari.di.application.module.AppModulesKt$appModules$1$3.invoke(appModules.kt:65)
at yodgorbek.komilov.musobaqayangiliklari.di.application.module.AppModulesKt$appModules$1$3.invoke(Unknown Source:4)
at org.koin.core.instance.DefinitionInstance.create(DefinitionInstance.kt:54)
... 44 more
_
tOPHEASLINESFRAGMENT.KT
クラスTopHeadLinesFragment:fragment(){
private val viewModel: MainViewModel by viewModel()
private lateinit var topHeadlinesAdapter: TopHeadlinesAdapter
//3
override fun onCreateView(
inflater: LayoutInflater,
container: ViewGroup?,
savedInstanceState: Bundle?
): View? {
val view = inflater.inflate(
R.layout.fragment_top_headlines
, container, false
)
val recyclerView = view.findViewById(R.id.recyclerView) as RecyclerView
val pb = view.findViewById(R.id.pb) as ProgressBar
topHeadlinesAdapter = TopHeadlinesAdapter(recyclerView.context)
recyclerView.layoutManager = LinearLayoutManager(context)
recyclerView.adapter = topHeadlinesAdapter
initViewModel()
return view
}
private fun initViewModel() {
viewModel?.sportList?.observe(this, Observer { newList ->
topHeadlinesAdapter.updateData(newList)
})
viewModel?.showLoading?.observe(this, Observer { showLoading ->
pb.visibility = if (showLoading) View.VISIBLE else View.GONE
})
viewModel?.showError?.observe(this, Observer { showError ->
(showError)
})
viewModel?.loadNews()
}
_
}
mainViewModel.kt以下
Suppress("UNCHECKED_CAST")
class MainViewModel(newsRepository: Any?) : ViewModel(), CoroutineScope {
// Coroutine's background job
val job = Job()
val sportNewsInterface: SportNewsInterface? = null
// Define default thread for Coroutine as Main and add job
override val coroutineContext: CoroutineContext = Dispatchers.Main + job
val showLoading = MutableLiveData<Boolean>()
val sportList = MutableLiveData <List<Article>>()
val showError = SingleLiveEvent<String>()
fun loadNews(
) {
// Show progressBar during the operation on the MAIN (default) thread
showLoading.value = true
// launch the Coroutine
launch {
// Switching from MAIN to IO thread for API operation
// Update our data list with the new one from API
val result = withContext(Dispatchers.IO) {
sportNewsInterface?.getNews()
}
// Hide progressBar once the operation is done on the MAIN (default) thread
showLoading.value = false
when (result) {
is UseCaseResult.Success<*> -> {
sportList.value = result.data as List<Article>
}
is Error -> showError.value = result.message
}
}
}
override fun onCleared() {
super.onCleared()
// Clear our job when the linked activity is destroyed to avoid memory leaks
job.cancel()
}
}
_
appmodules.ktの下に
const val BASE_URL = "https://newsapi.org/"
val appModules = module {
// The Retrofit service using our custom HTTP client instance as a singleton
single {
createWebService<SportNewsInterface>(
okHttpClient = createHttpClient(),
factory = RxJava2CallAdapterFactory.create(),
baseUrl = BASE_URL
)
}
// Tells Koin how to create an instance of CatRepository
factory<NewsRepository> { (NewsRepositoryImpl(sportNewsInterface = get())) }
// Specific viewModel pattern to tell Koin how to build MainViewModel
viewModel { MainViewModel (newsRepository = get ()) }
}
/* Returns a custom OkHttpClient instance with interceptor. Used for building Retrofit service */
fun createHttpClient(): OkHttpClient {
val client = OkHttpClient.Builder()
client.readTimeout(5 * 60, TimeUnit.SECONDS)
return client.addInterceptor {
val original = it.request()
val requestBuilder = original.newBuilder()
requestBuilder.header("Content-Type", "application/json")
val request = requestBuilder.method(original.method, original.body).build()
return@addInterceptor it.proceed(request)
}.build()
}
/* function to build our Retrofit service */
inline fun <reified T> createWebService(
okHttpClient: OkHttpClient,
factory: CallAdapter.Factory, baseUrl: String
): T {
val retrofit = Retrofit.Builder()
.baseUrl(baseUrl)
.addConverterFactory(GsonConverterFactory.create(GsonBuilder().setLenient().create()))
.addCallAdapterFactory(CoroutineCallAdapterFactory())
.addCallAdapterFactory(factory)
.client(okHttpClient)
.build()
return retrofit.create(T::class.Java)
}
_
newsRepository.ktの下にNewsRepositoryを実装しました
interface NewsRepository {
// Suspend is used to await the result from Deferred
suspend fun getNewsList(): UseCaseResult<Deferred<List<SportNewsResponse>>>
}
class NewsRepositoryImpl(private val sportNewsInterface: SportNewsInterface) : NewsRepository {
override suspend fun getNewsList(): UseCaseResult<Deferred<List<SportNewsResponse>>> {
/*
We try to return a list of cats from the API
Await the result from web service and then return it, catching any error from API
*/
return try {
val result = sportNewsInterface.getNews()
UseCaseResult.Success(result) as UseCaseResult<Deferred<List<SportNewsResponse>>>
} catch (ex: Exception) {
UseCaseResult.Error(ex)
}
}
}
_
下の例のように、ダガー@pagrovides注釈と同じように「提供」条約を使用する必要があります。
val appModules = module {
fun provideNewsRepository(sportNewsInterface: SportNewsInterface): NewsRepository {
return NewsRepositoryImpl(sportNewsInterface)
}
fun provideSportNewsInterface(): SportNewsInterface {
return createWebService < SportNewsInterface > (
okHttpClient = createHttpClient(),
factory = RxJava2CallAdapterFactory.create(),
baseUrl = BASE_URL
)
}
single {
provideNewsRepository(get())
}
single {
provideSportNewsInterface()
}
viewModel {
MainViewModel(newsRepository = get())
}
}
_
ネットワークモジュールにAPIインターフェイスのインスタンスを作成することを忘れた可能性があります。私のネットワーキングモジュールクラスはこのようになります。
val networkingModule = module {
single { GsonConverterFactory.create() as Converter.Factory }
single { HttpLoggingInterceptor().setLevel(HttpLoggingInterceptor.Level.BODY) as Interceptor }
single {
OkHttpClient.Builder().apply {
if (BuildConfig.DEBUG) addInterceptor(get())
.callTimeout(10, TimeUnit.SECONDS)
}.build()
}
single {
Retrofit.Builder()
.baseUrl(BuildConfig.Host)
.client(get())
.addConverterFactory(get())
.build()
}
single { get<Retrofit>().create(LoginService::class.Java) }
single { get<Retrofit>().create(BlockService::class.Java) }
single { get<Retrofit>().create(ForgotPasswordService::class.Java) }
}
_
私の場合は、/
を追加しました。私はから変わりました
single(named("baseUrl")) { "https://yourwebsite.net/api" }
に
single(named("baseUrl")) { "https://yourwebsite.net/api/" }