I was developing an Kotlin App which connect which a test API usig Retrofit 2.
And everythings fine until I try to implement a query which let the user filter by id the call to the API.
so I'm getting the above title error
Regarding my clases are the following:
MainActivity.kt
@AndroidEntryPoint
class MainActivity : AppCompatActivity() {
private lateinit var binding: ActivityMainBinding
private lateinit var id: Number
private val quoteViewModel: QuoteViewModel by viewModels()
private lateinit var userSearch: QuoteModel;
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)
var Etid: EditText = findViewById(R.id.EtId)
//Inicializamos el controlador UI-data (ViewModel)
quoteViewModel.onCreate()
//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
})
//No uso el binding porque fallaba el Dagger (Inyector de dependencias)
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
}
}
}
QuoteService.kt
@Singleton
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
}
}
QuoteProvider.kt
@Singleton
class QuoteProvider @Inject constructor() {
var allUsers: List<QuoteModel> = emptyList1()
var userById: QuoteModel? = null
}
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
}
}
Regarding the clases where I invoke the pulls, are the following.
GetAllUsers.kt
class GetAllUsers @Inject constructor(private val repository: QuoteRepository) {
suspend operator fun invoke() = repository.getAllUsers()
}
GetUsersById.kt
class GetUserById @Inject constructor(private val provider: QuoteProvider) {
//TODO() Si no funciona probar a sacarlo del repository.
suspend operator fun invoke(id: kotlin.Int): QuoteModel? {
//val id = id
return provider.userById
}
}
And finally my ViewModel:
QuoteViewModel.kt
@HiltViewModel
class QuoteViewModel @Inject constructor(
private val getAllUsers:GetAllUsers,
private val getUserById: GetUserById
) : ViewModel() {
val quoteModel = MutableLiveData<QuoteModel>()
val isLoading = MutableLiveData<Boolean>()
fun onCreate() {
viewModelScope.launch {
isLoading.postValue(true)
val result = getAllUsers()
if(!result.isNullOrEmpty()){
quoteModel.postValue(result[0])
isLoading.postValue(false)
}
}
}
fun getUserIdQuote(id: Int) {
viewModelScope.launch {
isLoading.postValue(true)
val quote = getUserById(id)
if (quote != null) {
quoteModel.postValue(quote)
}
isLoading.postValue(false)
}
}
}
[EDIT]
ADDED THE RETROFIT NETWORK CONNECTION:
QuoteApiClient.kt
interface QuoteApiClient {
@GET("/users")
suspend fun getAllUUsers(): Response<List<QuoteModel>>
@GET("/users/?{id}")
suspend fun getUserById(id: Number): Response<QuoteModel>
}
My QuoteModel.kt class
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,
) {
}
And the json response to https://jsonplaceholder.typicode.com/users return an array of object like this:
[
{
"id": 1,
"name": "Leanne Graham",
"username": "Bret",
"email": "[email protected]",
"address": {
"street": "Kulas Light",
"suite": "Apt. 556",
"city": "Gwenborough",
"zipcode": "92998-3874",
"geo": {
"lat": "-37.3159",
"lng": "81.1496"
}
},
"phone": "1-770-736-8031 x56442",
"website": "hildegard.org",
"company": {
"name": "Romaguera-Crona",
"catchPhrase": "Multi-layered client-server neural-net",
"bs": "harness real-time e-markets"
}
},
I hope you know how refers that kind of error, which obviously implicated the way to manipulated the data when I connect to API.
So if you can help, take that in advance !
CodePudding user response:
In your data object QuoteModel
you have address as a string value
@SerializedName("address") val addrees: String
and company as a string value
@SerializedName("company") val company: String
Your Json those values are objects
Address object
"address": {
"street": "Kulas Light",
"suite": "Apt. 556",
"city": "Gwenborough",
"zipcode": "92998-3874",
"geo": {
"lat": "-37.3159",
"lng": "81.1496"
}
}
Company object
"company": {
"name": "Romaguera-Crona",
"catchPhrase": "Multi-layered client-server neural-net",
"bs": "harness real-time e-markets"
}
You need to create address and company objects for you data class