我正在开发新闻,并且已经在一个片段中实现了ViewModel。 但是,我的应用程序崩溃了。
以下是我在logcat中收到的错误:
java.lang.RuntimeException: Cannot create an instance of class yodgorbek.komilov.musobaqayangiliklari.viewmodel.MainViewModel
at androidx.lifecycle.ViewModelProvider$NewInstanceFactory.create(ViewModelProvider.java:184)
at androidx.lifecycle.ViewModelProvider$AndroidViewModelFactory.create(ViewModelProvider.java:241)
at androidx.lifecycle.ViewModelProvider.get(ViewModelProvider.java:164)
at androidx.lifecycle.ViewModelProvider.get(ViewModelProvider.java:130)
at yodgorbek.komilov.musobaqayangiliklari.ui.TopHeadlinesFragment.onCreateView(TopHeadlinesFragment.kt:58)
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:1425)
at android.app.Activity.performStart(Activity.java:7825)
at android.app.ActivityThread.handleStartActivity(ActivityThread.java:3294)
at android.app.servertransaction.TransactionExecutor.performLifecycleSequence(TransactionExecutor.java:221)
at android.app.servertransaction.TransactionExecutor.cycleToPath(TransactionExecutor.java:201)
at android.app.servertransaction.TransactionExecutor.executeLifecycleState(TransactionExecutor.java:173)
at android.app.servertransaction.TransactionExecutor.execute(TransactionExecutor.java:97)
at android.app.ActivityThread$H.handleMessage(ActivityThread.java:2016)
at android.os.Handler.dispatchMessage(Handler.java:107)
at android.os.Looper.loop(Looper.java:214)
at android.app.ActivityThread.main(ActivityThread.java:7356)
at java.lang.reflect.Method.invoke(Native Method)
at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:492)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:930)
Caused by: java.lang.InstantiationException: java.lang.Class<yodgorbek.komilov.musobaqayangiliklari.viewmodel.MainViewModel> has no zero argument constructor
at java.lang.Class.newInstance(Native Method)
at androidx.lifecycle.ViewModelProvider$NewInstanceFactory.create(ViewModelProvider.java:182)
下面是我的MainViewModel.kt
class MainViewModel(newsRepository: NewsRepository) : 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()
}
}
下面是我的MainViewModelFactory.kt
class MainViewModelFactory(
private val someParameter: NewsRepository
) : ViewModelProvider.NewInstanceFactory() {
override fun <T : ViewModel> create(modelClass: Class<T>): T {
return MainViewModel(someParameter) as T
}
}
下面是我的TopHeadlinesFragment.kt
class TopHeadlinesFragment : Fragment() {
private var viewModel: MainViewModel? = null
private lateinit var topHeadlinesAdapter: TopHeadlinesAdapter
private var newsRepository: NewsRepository? = null
//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
val param = newsRepository
val factory = param?.let { MainViewModelFactory(it) }
viewModel = ViewModelProviders.of(this, factory).get(MainViewModel::class.java)
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()
}
}
NewsRepository.kt
interface NewsRepository {
// Suspend is used to await the result from Deferred
suspend fun getNewsList(): UseCaseResult<List<Article>>
}
class NewsRepositoryImpl(private val sportNewsInterface: SportNewsInterface) : NewsRepository {
override suspend fun getNewsList(): UseCaseResult<List<Article>> {
return try {
val result = sportNewsInterface.getNews()
UseCaseResult.Success(result) as UseCaseResult<List<Article>>
} catch (ex: Exception) {
UseCaseResult.Error(ex)
}
}
}
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)
}
请让我知道如何解决此崩溃
我遵循了一种描述为here
的方法答案 0 :(得分:-1)
您的ViewModelFactory必须具有NewsRepository
才能构造ViewModel。但是您的newRepository未初始化,因此工厂未初始化。再次检查代码。
更新: OP正在使用Koin进行依赖项注入,却忘记将NewsRepository注入碎片中。
通过使用private val newsRepository: newsRepository by inject()