【发布时间】:2021-09-22 10:19:06
【问题描述】:
我正在开发一个 Retrofit 2 kotlin 应用程序,一切都很好,直到我尝试实现另一个功能,让用户通过 id 过滤到不同用户的 API。
应用程序的第一种工作方式是调用所有用户,并在我的 ViewModel 的 onClick 侦听器中恢复其中一个,并显示在屏幕上。
所以,我尝试做同样的事情,但我添加了一个 EditText 让用户按 id 过滤,当我实现该功能时,我开始收到以下错误:
error: [Dagger/MissingBinding] java.lang.Integer cannot be provided without an @Inject constructor or an @Provides-annotated method.
所以,我的 kotlin 类如下:
MainActivity.kt
@AndroidEntryPoint
class MainActivity : AppCompatActivity() {
private lateinit var binding: ActivityMainBinding
private lateinit var Etid: EditText
private lateinit var id: Number
private val quoteViewModel: QuoteViewModel by viewModels()
private var userSearch: QuoteModel = TODO()
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
//Pasa el layout a linkear con el binding.
binding = ActivityMainBinding.inflate(layoutInflater)
//settemos la vista
setContentView(binding.root)
//Inicilizamos el controlador UI-data (ViewModel)
quoteViewModel.onCreate()
//Inicilizamos el EditText.
Etid.findViewById(R.id.EtId) as EditText
//Establecemos un observer en los datos
quoteViewModel.quoteModel.observe(this, Observer {
binding.tvName.text = it.name
binding.tvEmail.text = it.email
binding.tvAddress.text = it.addrees
binding.tvPhone.text = it.phone
binding.tvWebsite.text = it.website
binding.tvCompany.text = it.company
})
//Establecemos un observer en la carga de la página.
quoteViewModel.isLoading.observe(this, Observer {
binding.loading.isVisible = it
})
binding.viewContainer.setOnClickListener {
id = Etid.id;
userSearch = quoteViewModel.getUserIdQuote(id as Int) as QuoteModel
it.findViewById<TextView>(R.id.tvName).text = userSearch.name
it.findViewById<TextView>(R.id.tvAddress).text = userSearch.addrees
it.findViewById<TextView>(R.id.tvCompany).text = userSearch.company
it.findViewById<TextView>(R.id.tvEmail).text = userSearch.email
it.findViewById<TextView>(R.id.tvPhone).text = userSearch.phone
it.findViewById<TextView>(R.id.tvWebsite).text = userSearch.website
}
}
}
关于我的改造配置:
NetworkModule.kt
@Module
@InstallIn(SingletonComponent::class)
object NetworkModule {
@Singleton
@Provides
fun provideRetrofit():Retrofit{
return Retrofit.Builder()
.baseUrl("https://jsonplaceholder.typicode.com/")
.addConverterFactory(GsonConverterFactory.create())
.build()
}
@Singleton
@Provides
fun provideQuoteApiClient(retrofit: Retrofit):QuoteApiClient{
return retrofit.create(QuoteApiClient::class.java)
}
}
我的数据模型如下:
data class QuoteModel(
@SerializedName("id") val quote: Number,
@SerializedName("name") val name: String,
@SerializedName("email") val email: String,
@SerializedName("address") val addrees: String,
@SerializedName("phone") val phone: String,
@SerializedName("website") val website: String,
@SerializedName("company") val company: String,
)`
我的提供者服务和存储库是:
QuoteProvider.kt
@Singleton
class QuoteProvider @Inject constructor() {
var allUsers: List<QuoteModel> = emptyList1()
var userById: QuoteModel = listOf<QuoteModel>() as QuoteModel
}
`
QuoteService.kt
class QuoteService @Inject constructor(private val api:QuoteApiClient) {
suspend fun getAllUsers(): List<QuoteModel> {
return withContext(Dispatchers.IO) {
val response = api.getAllUUsers()
response.body() ?: emptyList1()
}
}
suspend fun getUserById(id:Number): QuoteModel{
return withContext(Dispatchers.IO){
val response = api.getUserById(id)
response.body() ?: listOf<QuoteModel>()
} as QuoteModel
}
}
QuoteRepository.kt
class QuoteRepository @Inject constructor(
private val api: QuoteService,
private val quoteProvider: QuoteProvider
) {
suspend fun getAllUsers(): List<QuoteModel> {
//extraemos los users de la api
val response = api.getAllUsers()
//Le pasamos el [] de users al repository de la app.
quoteProvider.allUsers = response
return response
}
suspend fun getUserById(id: Number): QuoteModel {
//Recogemos el usuario pasandole el Id al QueryRepository
val response = api.getUserById(id)
quoteProvider.userById = response
return response
}
}
最后我通过twot clases控制了对repository的调用,不知道是不是这样用的。
class GetUserById @Inject constructor(private val repository: QuoteRepository, private var id: Int) {
//TODO() Si no funciona probar a sacarlo del repository.
suspend operator fun invoke(id: kotlin.Int): QuoteModel {
//val id = id
return repository.getUserById(id)
}
}
和
class GetAllUsers @Inject constructor(private val repository: QuoteRepository) {
suspend operator fun invoke() = repository.getAllUsers()
}
也许错误可能在实现的结构中,而不是某些类的错误代码
希望您对改造的使用有一定的了解,可以提供帮助。
如果是这样,请提前感谢!
【问题讨论】:
-
从
GetUserById构造函数中删除private var id: Int -
还有
listOf<QuoteModel>() as QuoteModel看起来很奇怪,会导致ClassCastException -
你是对的。你的建议解决了我的问题,但知道我在你提到的那一行中得到了 ClassCastException。我可以实例化一个空的 QuoteModel,就像使用 emptyList()
-
idk "empty QuoteModel" 是什么意思,如果没有对象,您可以返回
null,或者您可以使用空字段创建实例QuoteModel(0, "", ...)