Hello, I want get the objects from users array fro...
# android
h
Hello, I want get the objects from users array from API using Moshi , but I get non understandable error  'Inferred type is UserResponse but User was expected' in  setupObserver(). What mistake did I make? Thanks in advance.
Copy code
{
  "users": [
    {
      "id": "1",
      "name": "Bill Roy",
    },
     {
      "id": "2",
      "name": "Ben Bush",
    },
    {
      "id": "3",
      "name": "Dan Fox",
    },
  ]
}
User.kt
Copy code
data class User(
    @Json(name = "id")
    val id: Int = 0,
    @Json(name = "name")
    val name: String = ""
)
data class UserResponse(
    @Json(name = "users")
    val userList: List<User>
)
MainViewModel.kt
Copy code
class MainViewModel(
    private val mainRepository: MainRepository,
    private val networkHelper: NetworkHelper
) : ViewModel() {

    private val _users = MutableLiveData<Resource<UserResponse>>()
    val users: LiveData<Resource<UserResponse>>
        get() = _users

    init {
        fetchUsers()
    }

    private fun fetchUsers() {
        viewModelScope.launch {
            _users.postValue(Resource.loading(null))
            if (networkHelper.isNetworkConnected()) {
                mainRepository.getUsers().let {
                    if (it.isSuccessful) {
                        _users.postValue(Resource.success(it.body()))

                    } else _users.postValue(Resource.error(it.errorBody().toString(), null))
                }
            } else _users.postValue(Resource.error("No internet connection", null))
        }
    }
}
 MainAdapter.kt
Copy code
class MainAdapter(
    private val users: ArrayList<User>
) : RecyclerView.Adapter<MainAdapter.DataViewHolder>() {

    class DataViewHolder(itemView: View) : RecyclerView.ViewHolder(itemView) {
        fun bind(user: User) {
            itemView.textViewUserName.text = user.name
        }
    }

    override fun onCreateViewHolder(parent: ViewGroup, viewType: Int) =
        DataViewHolder(
            LayoutInflater.from(parent.context).inflate(
                R.layout.item_layout, parent,
                false
            )
        )

    override fun getItemCount(): Int = users.size

    override fun onBindViewHolder(holder: DataViewHolder, position: Int) =
        holder.bind(users[position])

    fun addData(list: User) {
        users.addAll(listOf(list))
    }
}
MainActivity.kt
Copy code
private fun setupObserver() {
    mainViewModel.users.observe(this, Observer {
        when (it.status) {
            Status.SUCCESS -> {
                progressBar.visibility = View.GONE
                it.data?.let { users -> renderList(users) }          
                recyclerView.visibility = View.VISIBLE
            }........
}

 private fun renderList(users: User) {
        adapter.addData(users)                             
        adapter.notifyDataSetChanged()
    }
😶 1
l
Check the type on
renderList()
it should be
renderList(response: UserResponse)
instead of what you have
h
@Luis, thanks for your reply. If I do it, addData() function's argument must be changed and in this case adapter will not work
l
Yes, you are right. Look at the types you are passing around. You have a
UserResponse
with a
userList
property. The type coming from your response is
UserResponse
and the type your adapter needs is
List<User>
You need to pass the right thing to the
renderList()
method, so Kotlin type checker is telling you that you can give
UserResponse
to something expecting
User
Like I said, the method should be declared like
renderList(response: UserResponse)
and then you need to pass `response.userList`to the adapter
h
@Luis, I've done it, but I get the same error again.
Copy code
MainAdapter.kt
class MainAdapter(
    private val users: ArrayList<User>
) : RecyclerView.Adapter<MainAdapter.DataViewHolder>() {
    class DataViewHolder(itemView: View) : RecyclerView.ViewHolder(itemView) {
        fun bind(user: User) {
            itemView.textViewUserName.text = user.name
        }
    }
    override fun onCreateViewHolder(parent: ViewGroup, viewType: Int) =
        DataViewHolder(
            LayoutInflater.from(parent.context).inflate(
                R.layout.item_layout, parent,
                false
            )
        )
    override fun getItemCount(): Int = users.size
    override fun onBindViewHolder(holder: DataViewHolder, position: Int) =
        holder.bind(users[position])

 fun addData(list: List<User>) {
        users.addAll(list)
    }
}
MainActivity.kt
Copy code
private fun setupObserver() {
    mainViewModel.users.observe(this, Observer {
        when (it.status) {
            Status.SUCCESS -> {
                progressBar.visibility = View.GONE
                it.data?.let {userResponse ->  renderList(userResponse)}       
                recyclerView.visibility = View.VISIBLE
            }........
}

 private fun renderList(users: UserResponse) {
        adapter.addData(users.userList)
        adapter.notifyDataSetChanged()
    }
l
Well, my compile in head skills say its seems fine. The error message should tell you the line where it is failing to compile
h
@Luis, the errors show on adapter.addData(users.userList), renderList() and it.data?.let {userResponse -> renderList(userResponse)}
l
Hey, it seems to me you are still learning the language, this type of problems are easy to understand and fix if you have a better understanding of what you are working on. The error message is telling you where the problem is and what to do to fix it, so I think you might need to take a step back and do some tutorials on Kotlin to understand what is happening. I can recommend either this: https://developer.android.com/kotlin/learn The w3schools one is also cool: https://www.w3schools.com/kotlin/index.php
💯 1
I am willing to help you solve any problems you find, but at this point am I writing the code for you, so you should learn Kotlin to a point where you can fix these issues by yourself
h
@Luis I can send you my project instead of your writing code for me. If I don't use the array of of objects in API and use only User data class, the app works