Kotlin: How to fetch data from web service and display it in app? - api

Hello :) I'm working on app that shows popular movies and some details about each of them. I created a RecyclerView where information should be displayed. I'm stuck with getting and displaying data. I'm using https://www.themoviedb.org/ page for api.
I was following these steps: http://imakeanapp.com/make-a-movies-app-using-tmdb-api-part-4-networking-using-retrofit-library/ , but it's written in Java and I need code in Kotlin. I converted by myself a part of the code, here is what I have:
in Movie.kt
data class Movie (
#SerializedName("id") val id: Int,
#SerializedName("title") val title: String,
#SerializedName("poster_path") val posterPath: String,
#SerializedName("release_date") val releaseDate: String,
#SerializedName("vote_average") val rating: Float
)
in MoviesResponse.kt
data class MoviesResponse (
#SerializedName("page") val page: Int,
#SerializedName("total_results") val totalResults: Int,
#SerializedName("results") val movies: List<Movie>,
#SerializedName("total_pages") val totalPages: Int
)
in TMDbApi.kt
interface TMDbApi {
#GET("movie/popular")
fun getPopularMovies (
#Query("api_key") apiKey: String,
#Query("language") language: String,
#Query("page") page: Int
): Call<List<MoviesResponse>>
}
in OnGetMoviesCallback.kt
interface OnGetMoviesCallback {
fun onSuccess(movies: List<Movie>)
fun onError()
}
in MainAdapter.kt
class MainAdapter: RecyclerView.Adapter<CustomHolder>(){
var movies: List<Movie> = listOf()
fun MainAdapter(movies: List<Movie>) {
this.movies = movies
}
override fun getItemCount(): Int {
return movies.size
}
override fun onBindViewHolder(holder: CustomHolder, position: Int) {
holder.bind(movies.get(position))
holder?.setOnClick()
}
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): CustomHolder {
val layoutInflater = LayoutInflater.from(parent?.context)
val cellForRow = layoutInflater.inflate(R.layout.movie_row, parent, false)
return CustomHolder(cellForRow)
}
}
class CustomHolder(view: View): RecyclerView.ViewHolder(view){
fun bind(result: Movie){
itemView.title.text = result.title
itemView.release_date.text = result.releaseDate
}
}
in MoviesRepository.kt
val BASE_URL: String = "https://api.themoviedb.org/3/"
val LANGUAGE: String = "en-US"
data class MoviesRepository (
val repositroy: MoviesRepository,
val api: TMDbApi
)
object getInstance{
val retrofit: TMDbApi = Retrofit.Builder()
.addConverterFactory(GsonConverterFactory.create())
.client(OkHttpClient().newBuilder().build())
.baseUrl(BASE_URL)
.build()
.create(TMDbApi::class.java)
}
in AllMoviesActivity.kt
class AllMoviesActivity : AppCompatActivity(), Callback<List<MoviesResponse>> {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_all_movies)
rw_main.layoutManager = LinearLayoutManager(this)
rw_main.adapter = MainAdapter()
getMovies()
}
private fun getMovies() {
getInstance.retrofit.getPopularMovies("2B0b0e8d104f0d6130a4fc67848f89e107", LANGUAGE, 1).enqueue(this)
}
override fun onResponse(call: retrofit2.Call<List<MoviesResponse>>, response: Response<List<MoviesResponse>>) {
val moviesResponse = response.body() ?: listOf()
Log.d("Results", moviesResponse.toString())
}
override fun onFailure(call: retrofit2.Call<List<MoviesResponse>>, t: Throwable) {
Toast.makeText(this, "Failed", Toast.LENGTH_SHORT).show()
}
}
And I have added in Manifest file Internet permission. When I run this, I get 'Failed' Toast and I don't see RecyclerView. Can you tell me what I'm missing or what's wrong? I've been searching on the Internet solutions but with no results. Hope you could help me. Thanks!

Looks like you are missing something small. After making a call to the API on Postman, Here's what you expect on your response body:
{
"page": 1,
"total_results": 10000,
"total_pages": 500,
"results": [...
}
Having brought that up, lets digest your lines, in TMDbApi.kt, you have indicated that your expected response is a List<MoviesResponse> which conflicts the response you receive as it is a JSON of type MoviesResponse,
Fix:
...): Call<List<MoviesResponse>>
}
to:
): Call<MoviesResponse>
}
The rest are small fixes to align your response handling.
Head over to AllMoviesActivity.kt and change the following:
class AllMoviesActivity : AppCompatActivity(), Callback<List<MoviesResponse>> {
to
class MainActivity : AppCompatActivity(), Callback<MoviesResponse>
Then on the callback functions, change signatures like so:
override fun onResponse(call: retrofit2.Call<List<MoviesResponse>>, response: Response<List<MoviesResponse>>) {
val moviesResponse = response.body() ?: listOf() ...
to:
override fun onResponse(call: Call<MoviesResponse>, response:Response<MoviesResponse>
) {
val moviesResponse = response.body()//type will be inferred ...
Then finally,
override fun onFailure(call: retrofit2.Call<List<MoviesResponse>>, t: Throwable) {
to:
override fun onFailure(call: Call<MoviesResponse>, t: Throwable) {
That's the basic to get the response and keep the Failure toast at bay.
Parting shot
Make the logs your friend, they can reveal the messy & smallest misses

Related

How to make functions wait result

I'm newbie in coding, so I want to ask more experienced programmers how to do it right.
I have 2 functions, first from Facebook SDK and second from AppsFlyerLib.
Can you tell me if there is right option to wait results from this functions please.
Here example of code:
class MainActivity: AppCompatActivity() {
override fun onCreate(savedInstanceState: Bundle?, persistentState: PersistableBundle?) {
super.onCreate(savedInstanceState, persistentState)
var linkdataPlusApps = ""
//Getting Link Data
val linkdataHandler = object : AppLinkData.CompletionHandler {
override fun onDeferredAppLinkDataFetched(appLinkData: AppLinkData?) {
linkdataPlusApps += appLinkData.toString()
}
}
AppLinkData.fetchDeferredAppLinkData(this, linkdataHandler)
//Gettings Apps
val appsdataHandler = object : AppsFlyerConversionListener {
override fun onConversionDataSuccess(p0: MutableMap<String, Any>?) {
linkdataPlusApps += p0.toString()
}
override fun onConversionDataFail(p0: String?) {}
override fun onAppOpenAttribution(p0: MutableMap<String, String>?) {}
override fun onAttributionFailure(p0: String?) {}
}
AppsFlyerLib.getInstance().init("APPS_KEY", appsdataHandler, this).start(this)
//Here I wanna take this data and put in another activity
val intent = Intent(this, NextActivity::class.java)
intent.putExtra("FetchedData", linkdataPlusApps)
startActivity(intent)
}}
But this code doesn't work because Activity started before data was fetched so string is empty.
I solved this by chaining code, but I'm sure that is dirty-coding.
How I did
class MainActivity: AppCompatActivity() {
override fun onCreate(savedInstanceState: Bundle?, persistentState: PersistableBundle?) {
super.onCreate(savedInstanceState, persistentState)
var linkdataPlusApps = ""
//Getting Link Data
val linkdataHandler = object : AppLinkData.CompletionHandler {
override fun onDeferredAppLinkDataFetched(appLinkData: AppLinkData?) {
linkdataPlusApps += appLinkData.toString()
val appsdataHandler = object : AppsFlyerConversionListener {
override fun onConversionDataSuccess(p0: MutableMap<String, Any>?) {
linkdataPlusApps += p0.toString()
val intent = Intent(this#MainActivity, NextActivity::class.java)
intent.putExtra("FetchedData", linkdataPlusApps)
startActivity(intent)
}
override fun onConversionDataFail(p0: String?) {}
override fun onAppOpenAttribution(p0: MutableMap<String, String>?) {}
override fun onAttributionFailure(p0: String?) {}
}
AppsFlyerLib.getInstance().init("APPS_KEY", appsdataHandler, this#MainActivity).start(this#MainActivity)
}
}
AppLinkData.fetchDeferredAppLinkData(this, linkdataHandler)
}
}
So code starts from fetching AppLinkData, and when fetched, starting fetching apps, and only then starting second activity with right string.
Can I do it in another way?

I want to use recyclerView, but the view doesn't have any values. kotlin

class SummonerInfoActivity: AppCompatActivity() {
private lateinit var participantAdapter: ParticipantAdapter
private val recycler: RecyclerView by lazy {
findViewById(R.id.RecyclerView)
}
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
val Summoner = intent.getParcelableExtra<SummonerDTO>("SummonerDTO")
Log.e("Info","${Summoner}")
val retrofit2 = Retrofit.Builder()
.baseUrl("https://asia.api.riotgames.com")
.addConverterFactory(GsonConverterFactory.create())
.build()
lolAPIForMatch = retrofit2.create(lolAPIService::class.java)
setContentView(R.layout.activity_summoner_info)
participantAdapter = ParticipantAdapter()
recycler.adapter = participantAdapter
recycler.layoutManager = LinearLayoutManager(this#SummonerInfoActivity)
getMatchIdBypuuid(Summoner?.puuId.orEmpty(),Summoner?.summonerName.orEmpty())
}
private fun getMatchIdBypuuid(puuid: String,summonerName: String){
lolAPIForMatch.getMatchIdBypuuid(puuid, 0,20, API_KEY)
.enqueue(object : Callback<List<String>> {
override fun onResponse(
call: Call<List<String>>,
response: Response<List<String>>
) {
if(response.isSuccessful.not()){
return
}
response.body()?.let {
it.forEach {
searchMatchInfoByMatchID(it,summonerName)
}
}
}
override fun onFailure(call: Call<List<String>>, t: Throwable) {
}
})
}
private fun searchMatchInfoByMatchID(matchId: String,summonerName: String){
lolAPIForMatch.getMatchInfoByMatchID(matchId, API_KEY)
.enqueue(object : Callback<MatchDTO>{
override fun onResponse(call: Call<MatchDTO>, response: Response<MatchDTO>) {
if(response.isSuccessful.not()){
return
}
response.body()?.let {
it.info.participants.filter {
it.summonerName == "${summonerName}"
}.forEach {
participantAdapter.participants.add(it)
}
}
}
override fun onFailure(call: Call<MatchDTO>, t: Throwable) {
}
})
}
}
class ParticipantAdapter: RecyclerView.Adapter<ParticipantAdapter.ViewHolder>() {
var participants = mutableListOf<ParticipantDTO>()
inner class ViewHolder(itemView: View): RecyclerView.ViewHolder(itemView){
fun bind(participant: ParticipantDTO){
itemView.findViewById<TextView>(R.id.kill).text = participant.kills.toString()
itemView.findViewById<TextView>(R.id.death).text = participant.deaths.toString()
itemView.findViewById<TextView>(R.id.assist).text = participant.assists.toString()
}
}
override fun onCreateViewHolder(
parent: ViewGroup,
viewType: Int
): ParticipantAdapter.ViewHolder {
val inflater = LayoutInflater.from(parent.context)
return ViewHolder(inflater.inflate(R.layout.item_match, parent, false))
}
override fun onBindViewHolder(holder: ParticipantAdapter.ViewHolder, position: Int) {
holder.bind(participants[position])
}
override fun getItemCount(): Int {
return participants.size
}
}
participantAdapter.participants.add(it)
The command is searchMatchInfoByMatchID
In the function, you can check that the value is entered correctly, but
If you check in the onCreate function, the value is not assigned.
I want to use the recycler view by properly assigning a value
I tried to solve this problem, but my skills were not enough.
I desperately need the advice of seniors.
I would really appreciate it if you could show me a code sample if possible

Room cannot verify the data integrity. Looks like you've changed schema.... What's wrong?

I am using Room in my app with two entities. The whole implementation is below.
The Problem is, the given scheme is fixed, which means I do not change anything regarding DB. When I provide a new version of my app to Users over Google Play Console, I get the following issue in Cryshlytics although I did not change anything for DB, just edited UI or another things, which definetly nothing have to do with DB:
Fatal Exception: java.lang.IllegalStateException: Room cannot verify the data integrity. Looks like you've changed schema but forgot to update the version number. You can simply fix this by increasing the version number.
at androidx.room.RoomOpenHelper.checkIdentity(RoomOpenHelper.java:154)
at androidx.room.RoomOpenHelper.onOpen(RoomOpenHelper.java:135)
.......
Now I am not sure if I change the version of DB, it would work. What is wrong here?
BTW the DB is called from a Fragment like this
val mainDb: MainRepository by lazy { MainRepository(requireContext()) }
val stateDb: StateRepository by lazy { StateRepository(requireContext()) }
What's wrong here?
AppDatabase:
#Database(entities = [Main::class, State::class], version = 1, exportSchema = false)
abstract class AppDatabase : RoomDatabase() {
abstract val mainDao: MainDao
abstract val stateDao: StateDao
companion object {
private var INSTANCE: AppDatabase? = null
fun getInstance(context: Context): AppDatabase? =
INSTANCE ?: synchronized(AppDatabase::class) {
INSTANCE = Room.databaseBuilder(
context.applicationContext,
AppDatabase::class.java,
MY_DB
).allowMainThreadQueries()
.build()
return INSTANCE
}
}
}
Dao:
#Dao
interface StateDao {
#Query("SELECT * FROM $STATE")
fun getAll(): List<State>
#Insert(onConflict = OnConflictStrategy.REPLACE)
fun insert(state: State)
#Update
fun update(state: State)
#Query("DELETE FROM $STATE")
fun drop()
}
#Dao
interface MainDao {
#Query("SELECT * FROM $MAIN")
fun getAll(): List<Main>
#Insert(onConflict = OnConflictStrategy.REPLACE)
fun insert(main: Main)
#Update
fun update(main: Main)
#Query("DELETE FROM $MAIN")
fun drop()
}
Main:
#Entity(tableName = MAIN)
data class Main(
#PrimaryKey #ColumnInfo(name = NUMBER) val number: Int,
#ColumnInfo(name = CARD) val car: String? = EMPTY,
#ColumnInfo(name = MODEL) val model: String? = EMPTY
) : Parcelable {
constructor(parcel: Parcel) : this(
parcel.readInt(),
parcel.readString(),
parcel.readString()
)
override fun writeToParcel(parcel: Parcel, flags: Int) {
parcel.writeInt(number)
parcel.writeString(car)
parcel.writeString(model)
}
override fun describeContents(): Int {
return 0
}
companion object CREATOR : Parcelable.Creator<Main> {
override fun createFromParcel(parcel: Parcel): Main {
return Main(parcel)
}
override fun newArray(size: Int): Array<Main?> {
return arrayOfNulls(size)
}
}
}
State:
#Entity(tableName = STATE)
data class State(
#PrimaryKey #ColumnInfo(name = NUMBER) val number: Int,
#ColumnInfo(name = STATE) val state: String? = EMPTY
) : Parcelable {
constructor(parcel: Parcel) : this(
parcel.readInt(),
parcel.readString()
)
override fun writeToParcel(parcel: Parcel, flags: Int) {
parcel.writeInt(number)
parcel.writeString(question)
}
override fun describeContents(): Int {
return 0
}
companion object CREATOR : Parcelable.Creator<State> {
override fun createFromParcel(parcel: Parcel): State {
return State(parcel)
}
override fun newArray(size: Int): Array<State?> {
return arrayOfNulls(size)
}
}
}
Repository:
class MainRepository(context: Context) {
private val mainDao = AppDatabase.getInstance(context)?.mainDao
fun getAll(): List<Main>? {
return mainDao?.getAll()
}
fun insert(main: Main) {
AsyncInsert(mainDao).execute(main)
}
fun update(main: Main) {
mainDao?.update(main)
}
fun drop() {
mainDao?.drop()
}
private class AsyncInsert(private val dao: MainDao?) : AsyncTask<Main, Void, Void>() {
override fun doInBackground(vararg p0: Main?): Void? {
p0[0]?.let { dao?.insert(it) }
return null
}
}
}
class StateRepository(context: Context) {
private val stateDao = AppDatabase.getInstance(context)?.stateDao
fun drop() {
stateDao?.drop()
}
fun getAll(): List<State>? {
return stateDao?.getAll()
}
fun insert(state: State) {
AsyncInsert(stateDao).execute(state)
}
fun update(state: State) {
stateDao?.update(state)
}
private class AsyncInsert(private val dao: StateDao?) : AsyncTask<State, Void, Void>() {
override fun doInBackground(vararg p0: State?): Void? {
p0[0]?.let { dao?.insert(it) }
return null
}
}
}
Now I am not sure if I change the version of DB, it would work. What is wrong here?
Changing the version would probably not work as the schema, as far as Room is concerned, has changed.
There is either a bug or the schema has been changed.
However, changing the version, would, with a Migration that does nothing (so as to not get a "no migration specified" error), then fail but importantly with an expected (what Room expects the schema to be according to the Entities) found (the schema that exists) discrepancy. This, if there is no bug, could then be used to ascertain what has been changed.

I'm stuck, i can't pass data from model with api Rest, into another activity

I don't know why it's says me that "java.lang.IndexOutOfBoundsException: Index: 0, Size: 0"
I've been searching for this since 2 hours, and i don't know why there is this problem now, can you help me ? I want to pass data from apiRest into another activity with intent and putExtra/getExtra (I will do with firebase later, more simple and more easy way).
Main Activity
package com.mehdi.myapplication
class MainActivity : AppCompatActivity(), ListAdapter.OnItemClickListener {
lateinit var userAdapter: ListAdapter
var lm = LinearLayoutManager(this)
private val users: MutableList<Results> = mutableListOf()
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
initView()
getClassApiRet()
}
override fun onItemClick(position: Int) {
Toast.makeText(this, position.toString(), Toast.LENGTH_LONG).show()
val intent = Intent(this, DetailPageActivity::class.java)
intent.putExtra("email", users[position].email)
startActivity(intent)
}
fun initView() {
UserRecycleView.layoutManager = lm
userAdapter = ListAdapter(this, this)
UserRecycleView.adapter = userAdapter
}
fun getClassApiRet() {
val retro = Instance().getRetroInstance().create(ClassApiRest::class.java)
retro.getData().enqueue(object : Callback<ClassApi> {
override fun onResponse(call: Call<ClassApi>, response: Response<ClassApi>) {
val users = response.body()
runOnUiThread {
userAdapter.setUsers(users?.results!!)
}
}
override fun onFailure(call: Call<ClassApi>, t: Throwable) {
Log.e("Failed", t.message.toString())
}
})
}
}
UserInfo
class ClassApi {
#SerializedName("results")
#Expose
val results: List<Results>? = null
}
class Results {
#SerializedName("name")
#Expose
val name: Name? = null
#SerializedName("email")
#Expose
val email: String? = null
#SerializedName("login")
#Expose
val login: Login? = null
#SerializedName("picture")
#Expose
val picture: Picture? = null
}
class Name {
#SerializedName("title")
#Expose
val title: String? = null
#SerializedName("first")
#Expose
val first: String? = null
#SerializedName("last")
#Expose
val last: String? = null
}
class Login {
#SerializedName("username")
#Expose
val username: String? = null
}
class Picture {
#SerializedName("medium")
#Expose
val medium: String? = null
#SerializedName("large")
#Expose
val large: String? = null
}
ListAdapter
class ListAdapter(val context: Context, val listener: OnItemClickListener): RecyclerView.Adapter<ListAdapter.UsersViewHolder>() {
private val users: MutableList<Results> = mutableListOf()
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): ListAdapter.UsersViewHolder {
return UsersViewHolder(LayoutInflater.from(context).inflate(R.layout.row_user_list, parent, false))
}
override fun onBindViewHolder(holder: ListAdapter.UsersViewHolder, position: Int) {
holder.bindModel(users[position])
}
override fun getItemCount(): Int {
return users.size
}
fun setUsers(results: List<Results>) {
users.clear()
users.addAll(results)
notifyDataSetChanged()
}
inner class UsersViewHolder(item: View) : RecyclerView.ViewHolder(item), View.OnClickListener {
val UserImage: CircleImageView = item.findViewById(R.id.UserImage)
val UserName: TextView = item.findViewById(R.id.UserName)
val UserPseudo: TextView = item.findViewById(R.id.UserPseudo)
init {
itemView.setOnClickListener(this)
}
fun bindModel(b: Results) {
UserName.text = b.name?.first
UserPseudo.text = b.login?.username
val url = b.picture?.medium
Glide.with(UserImage)
.load(url)
.placeholder(R.drawable.ic_launcher_background)
.error(R.drawable.ic_launcher_background)
.fallback(R.drawable.ic_launcher_foreground)
.into(UserImage)
}
override fun onClick(v: View?) {
val position = adapterPosition
if (position != RecyclerView.NO_POSITION) {
listener.onItemClick(position)
}
}
}
interface OnItemClickListener {
fun onItemClick(position: Int)
}
}
Edit !!!
I think the probleme is with the position and the interface, he can't get data.
ListAdapter
override fun onClick(v: View?) {
val position = adapterPosition
if (position != RecyclerView.NO_POSITION) {
listener.onItemClick(position)
}
}
}
interface OnItemClickListener {
fun onItemClick(position: Int)
}
Main Activity
override fun onItemClick(position: Int) {
Toast.makeText(this, users[position].email.toString(), Toast.LENGTH_LONG).show()
val intent = Intent(this, DetailPageActivity::class.java)
//intent.putExtra("lolipop", users[position].toString())
startActivity(intent)
}
Your response listener is passing the list of users to the ListAdapter, but it doesn't do anything to the MainActivity's users property, so that list remains empty. Then your item click listener tries to access the user by index in that empty list.
I would remove the users property from the Activity since there is no practical use for it. In your ListAdapter, change the onItemClick function of the OnItemClickListener to pass the actual User instead of the User's position in the data. You can get the actual User using the adapterPosition from within the adapter, since it owns the users list.
Edit: I'm suggesting to change your listener function signature to return an item directly. There's no reason the Activity should have to find the item in the collection when the Adapter can just provide it directly.
// ListAdapter:
override fun onClick(v: View?) {
listener.onItemClick(users[adapterPosition])
}
interface OnItemClickListener {
fun onItemClick(results: Results)
}

Parsing api using Retrofit and GSON

I'm parsing API and it's logging in the logcat, but I have a problem while retrieving it and using that data in a recycleview. These are my code snippets:
class MainActivity : AppCompatActivity() {
private val users = arrayListOf<User>()
private lateinit var adapter: RecyclerViewAdapter
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
init()
}
private fun init() {
adapter = RecyclerViewAdapter(users)
recyclerView.layoutManager = LinearLayoutManager(this)
recyclerView.adapter = adapter
val myViewModel : UsersViewModel by viewModel()
myViewModel.getAllUsers().observe(this, Observer {
users.add(it)
adapter.notifyDataSetChanged()
})
myViewModel.getUsers()
d("allUsers", users.size.toString())
}
}
I cannot set the data in a recyclerview, can anyone give me a hint? I could not find a proper source or code snippet to understand how I'm able to parse the data using a converter.
class UsersRequest {
private var retrofit = Retrofit.Builder()
.baseUrl("https://reqres.in/api/")
.addConverterFactory(ScalarsConverterFactory.create())
.build()
private var service = retrofit.create(ApiService::class.java)
interface ApiService {
#GET("users?page=1")
fun getRequest(): Call<String>
}
fun getRequest(callback: CustomCallback) {
val call = service.getRequest()
call.enqueue(onCallback(callback))
}
private fun onCallback(callback: CustomCallback): Callback<String> = object : Callback<String> {
override fun onFailure(call: Call<String>, t: Throwable) {
d("response", "${t.message}")
callback.onFailure(t.message.toString())
}
override fun onResponse(call: Call<String>, response: Response<String>) {
d("response", "${response.body()}")
callback.onSuccess(response.body().toString())
}
}
}
class RecyclerViewAdapter(private val users: ArrayList<User>) :
RecyclerView.Adapter<RecyclerViewAdapter.ViewHolder>() {
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): ViewHolder {
return ViewHolder(
LayoutInflater.from(parent.context).inflate(
R.layout.user_layout,
parent,
false
)
)
}
override fun onBindViewHolder(holder: ViewHolder, position: Int) {
return holder.onBind()
}
override fun getItemCount() = users.size
private lateinit var user:User
inner class ViewHolder(itemView: View) : RecyclerView.ViewHolder(itemView) {
fun onBind() {
user = users[adapterPosition]
itemView.name.text = user.first_name
}
}
}
User(
val id: Int,
val email: String,
val first_name: String,
val last_name: String,
val avatar: String
)
with adapter class RecyclerViewAdapter(private val users: MutableList<User>) : RecyclerView.Adapter<RecyclerViewAdapter.ViewHolder>() { ...
Add this method to your adapter :
fun setUsers(usersList: List<User>) {
this.users.clear()
this.users.addAll(usersList)
notifyDataSetChanged()
}
and in MainActivity simply put :
myViewModel.getAllUsers().observe(this, Observer {
users -> hideLoading() // If you have a progress bar, here you can hide it
users?.let {
adapter.setUsers(users) }
})