This question already has answers here:
What is a NullPointerException, and how do I fix it?
(12 answers)
Closed 1 year ago.
Good day, I'm using Retrofit for the first time and I can't seem to get it to work. working on an app that get crypto currency rates in local currencies, here is the api [link], JSON format
Here are my models for News
data class News(
#field:SerializedName("totalResults")
val totalResults: Int,
#field:SerializedName("articles")
val articles: List<NewsArticle>?=null,
#field:SerializedName("status")
val status: String)
My model calss for NewsArticles:
data class NewsArticle(
#field:SerializedName("urlToImage")
val urlToImage: String? = null,
#field:SerializedName("description")
val description: String? = null,
#field:SerializedName("title")
val title: String? = null,
#field:SerializedName("url")
val url: String? = null,)
My interface:
const val BASE_URL = "https://saurav.tech/NewsAPI/"
interface NewsApiService {
#GET("top-headlines.json")
fun getNews(
#Query("category") category: String,
#Query("country_code") country_code: String
): Call<News>}
object NewsApi{
val newsInstance:NewsApiService
init {
val retrofit=Retrofit.Builder()
.baseUrl(BASE_URL).addConverterFactory(GsonConverterFactory.create())
.build()
newsInstance=retrofit.create(NewsApiService::class.java)
}
}
My MainActivity class
class MainActivity : AppCompatActivity() {
private lateinit var adapter: NewsAdapter
//var totalResult=1
private var article = mutableListOf<NewsArticle>()
lateinit var refreshLayout: SwipeRefreshLayout
private lateinit var recyclerView: RecyclerView
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
recyclerView = findViewById(R.id.recyclerViewNews)
refreshLayout = findViewById(R.id.refreshLayout)
adapter = NewsAdapter(this#MainActivity, article)
recyclerView.adapter = adapter
recyclerView.layoutManager = LinearLayoutManager(this#MainActivity)
fetchNews()
}
private fun fetchNews() {
val news = NewsApi.newsInstance.getNews("technology", "in")
news.enqueue(object : Callback<News> {
override fun onResponse(call: Call<News>, response: Response<News>) {
val news = response.body()
article.addAll(news!!.articles)
}
override fun onFailure(call: Call<News>, t: Throwable) {
Toast.makeText(applicationContext, t.message, Toast.LENGTH_SHORT).show()
}
})
}
}
My AdapterClass:
class NewsAdapter(val context: Context, val newsArticles: MutableList<NewsArticle>) :
RecyclerView.Adapter<NewsAdapter.NewsViewHolder>() {
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): NewsViewHolder {
val inflater = LayoutInflater.from(parent.context)
val view = inflater.inflate(R.layout.news_items, parent, false)
return NewsViewHolder(view)
}
override fun onBindViewHolder(holder: NewsViewHolder, position: Int) {
val article = newsArticles[position]
holder.title.text = article.title
holder.description.text = article.description
Glide.with(holder.itemView.context).load(article.urlToImage).into(holder.image)
}
override fun getItemCount() = newsArticles.size
class NewsViewHolder(view: View) : RecyclerView.ViewHolder(view) {
val title = view.findViewById<TextView>(R.id.titleText)!!
val description = view.findViewById<TextView>(R.id.descriptionText)!!
val image = view.findViewById<ImageView>(R.id.NewsImage)!!
}
}
When I run the code and check my log I get this error:
java.lang.NullPointerException
at com.ashish.technews.uis.MainActivity$fetchNews$1.onResponse(MainActivity.kt:44)
at retrofit2.DefaultCallAdapterFactory$ExecutorCallbackCall$1.lambda$onResponse$0$DefaultCallAdapterFactory$ExecutorCallbackCall$1(DefaultCallAdapterFactory.java:89)
at retrofit2.-$$Lambda$DefaultCallAdapterFactory$ExecutorCallbackCall$1$hVGjmafRi6VitDIrPNdoFizVAdk.run(lambda)
at android.os.Handler.handleCallback(Handler.java:754)
at android.os.Handler.dispatchMessage(Handler.java:95)
at android.os.Looper.loop(Looper.java:165)
at android.app.ActivityThread.main(ActivityThread.java:6375)
at java.lang.reflect.Method.invoke(Native Method)
at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:912)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:802)
What's Happening?
Article List in the response is not coming and it is not being handled properly.
Solution
Replace this: article.addAll(news!!.articles)
With this: news?.let { article.addAll(it.articles) }
Related
Hello Im working on project using Kotlin (for the first time). My problem is i don't know how to get data "fullname" inside "data" list where one of the data inside the list also getting use for the condition, the name is "Role" to my RecyclerView in my Activity.
So i need show list "fullname" inside my RecyclerView where the "Role" is "Patient".
Here is the DataFileRecord:
data class DataFileRecord(
#field:SerializedName("total")
val total: Int? = null,
#field:SerializedName("data")
val data: List<DataItem>? = null,
#field:SerializedName("offset")
val offset: Int? = null,
#field:SerializedName("limit")
val limit: Int? = null,
#field:SerializedName("status")
val status: Int? = null
)
//get fullname
data class DataItem(
#field:SerializedName("updateDate")
val updateDate: String? = null,
#field:SerializedName("departement")
val departement: Departement? = null,
#field:SerializedName("isBlock")
val isBlock: String? = null,
#field:SerializedName("role")
val role: Role? = null,
#field:SerializedName("fullname")
val fullname: String? = null,
#field:SerializedName("id")
val id: String? = null,
#field:SerializedName("username")
val username: String? = null
)
//get role = patient
data class Role(
#field:SerializedName("name")
val name: String? = null,
#field:SerializedName("id")
val id: String? = null
)
data class Departement(
#field:SerializedName("name")
val name: String? = null,
#field:SerializedName("id")
val id: String? = null
)
Here is my Adapter:
class PatientAdapter(val context: List<DataItem>) : RecyclerView.Adapter<PatientAdapter.MyViewHolder>() {
var patientList: List<DataItem> = listOf()
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): MyViewHolder {
val view = LayoutInflater.from(parent.context).inflate(R.layout.item_patient,parent,false)
return MyViewHolder(view)
}
override fun getItemCount(): Int {
return patientList.size
}
override fun onBindViewHolder(holder: MyViewHolder, position: Int){
holder.patientName.text = patientList.get(position).fullname
}
#SuppressLint("NotifyDataSetChanged")
fun setPatientListItems(patientList: List<DataItem>){
this.patientList=patientList
notifyDataSetChanged()
}
class MyViewHolder(itemView: View) : RecyclerView.ViewHolder(itemView) {
val patientName: TextView = itemView.findViewById(R.id.itemPatientName)
}
}
And here is where i stuck with my Call api in my activity:
//this 4 lines are inside oncreate
patientRecyclerView.setHasFixedSize(true)
linearLayoutManager = LinearLayoutManager(this)
patientRecyclerView.layoutManager = linearLayoutManager
patientRecyclerView.adapter = recyclerAdapter
fun getPatient(apiKey: String, apiSecret: String, token: String){
val retrofit = RetrofitClient.getClient()
retrofit.addGetPatient(apiKey,apiSecret,token)
.enqueue(object : Callback<DataFileRecord>{
override fun onResponse(call: Call<DataFileRecord>, response: Response<DataFileRecord>) {
TODO("Not yet implemented")
val dataPatient = response.body()
if (response.isSuccessful){
---------------- HERE WHERE I STUCK --------------------
}
}
override fun onFailure(call: Call<DataFileRecord>, t: Throwable) {
TODO("Not yet implemented")
}
})
}
Fragment into set list in adapter Code below :
binding.gvFolder.layoutManager = layoutManager
binding.gvFolder.adapter = AdapterGalleryPhotosFolder(this#GalleryImageFolderActivity,al_images,activityAddress)
below my Model class code:
data class ModelGalleryImagesFolder(val name:String, var al_imagepath: ArrayList<String>)
and below my full adapter code:
class AdapterGalleryPhotosFolder(
var context: Context,
var arrayList: ArrayList<ModelGalleryImagesFolder>,
var activityAddress: String?
):RecyclerView.Adapter<RecyclerView.ViewHolder>(){
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): RecyclerView.ViewHolder {
return MyViewHodler(AdapterPhotosfolderBinding.inflate(LayoutInflater.from(context),parent,false))
}
override fun onBindViewHolder(holder: RecyclerView.ViewHolder, position: Int) {
(holder as MyViewHodler)
val modelImages = arrayList[position]
holder.binding.tvFolder.text = modelImages.name
holder.binding.tvFolder2.text = arrayList[position].al_imagepath.size.toString()+" photo"
Glide.with(context).load(arrayList[position].al_imagepath[0])
.diskCacheStrategy(DiskCacheStrategy.NONE)
.skipMemoryCache(true)
.into(holder.binding.ivImage)
holder.binding.secondlayout.setOnClickListener {
val intent = Intent(context, GalleryImageFolderIntoImagesActivity::class.java)
intent.putExtra("position", position)
intent.putExtra("value", activityAddress)
context.startActivity(intent)
(context as Activity).finish()
}
}
override fun getItemCount(): Int {
return arrayList.size
}
class MyViewHodler(var binding: AdapterPhotosfolderBinding) : RecyclerView.ViewHolder(binding.root)
}
Got the answer.. just put this inside response= isSuccessfull
namePatient?.data?.filter { it.role?.name=="Pasien" }.let { if (it != null) { dataP.addAll(it) } }
reciAdapter.notifyDataSetChanged()
So "dataP" is my lateinit var MutableList, and "reciAdapter" is my Recycler Adapter Class
I am trying to parse JSON (https://raw.githubusercontent.com/Biuni/PokemonGO-Pokedex/master/pokedex.json) to show data in RecyclerView, but I get an error:
E/AndroidRuntime: FATAL EXCEPTION: main
Process: com.example.myapplication, PID: 13534
java.lang.IllegalStateException: Expected BEGIN_ARRAY but was BEGIN_OBJECT at line 1 column 2 path $
at com.google.gson.stream.JsonReader.beginArray(JsonReader.java:350)
at com.google.gson.internal.bind.CollectionTypeAdapterFactory$Adapter.read(CollectionTypeAdapterFactory.java:80)
at com.google.gson.internal.bind.CollectionTypeAdapterFactory$Adapter.read(CollectionTypeAdapterFactory.java:61)
at retrofit2.converter.gson.GsonResponseBodyConverter.convert(GsonResponseBodyConverter.java:39)
at retrofit2.converter.gson.GsonResponseBodyConverter.convert(GsonResponseBodyConverter.java:27)
at retrofit2.OkHttpCall.parseResponse(OkHttpCall.java:243)
at retrofit2.OkHttpCall$1.onResponse(OkHttpCall.java:153)
at okhttp3.internal.connection.RealCall$AsyncCall.run(RealCall.kt:519)
at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1167)
at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:641)
at java.lang.Thread.run(Thread.java:919)
I see that the problem is that JSON contains just 1 object (pokemon) and inside this object there is array of different pokemons. I don't know how to parse array inside the upper level object in JSON. What should I change to make it work?
I suppose that I should save this pokemon object and then parse it but I don't know hot to get inside it.
Thanks.
API interface:
interface SimpleApi {
#GET("pokedex.json")
suspend fun getCustomPosts(): Response<List<Post>>
}
Repository:
class Repository {
suspend fun getCustomPosts(): Response<List<Post>>{
return RetrofitInstance.api.getCustomPosts()
}
}
ViewModel:
class MainViewModel(val repository: Repository) : ViewModel() {
val myCustomPosts = MutableLiveData<Response<List<Post>>>()
fun getCustomPosts() {
viewModelScope.launch {
val response: Response<List<Post>> = repository.getCustomPosts()
myCustomPosts.value = response
}
}
}
MainActivity:
class MainActivity : AppCompatActivity() {
private lateinit var viewModel: MainViewModel
private lateinit var binding: ActivityMainBinding
private lateinit var recyclerView: RecyclerView
private lateinit var adapter: MyAdapter
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
binding = ActivityMainBinding.inflate(layoutInflater)
val view = binding.root
setContentView(view)
setRecyclerView()
val repository = Repository()
val viewModelFactory = MainViewModelFactory(repository)
viewModel = ViewModelProvider(this, viewModelFactory).get(MainViewModel::class.java)
viewModel.getCustomPosts()
viewModel.myCustomPosts.observe(this, Observer { response ->
if (response.isSuccessful) {
response.body()?.let { adapter.setData(it) }
} else {
Toast.makeText(this, response.code(), Toast.LENGTH_SHORT).show()
}
})
}
private fun setRecyclerView() {
adapter = MyAdapter()
recyclerView = binding.recyclerView
recyclerView.layoutManager = LinearLayoutManager(this)
recyclerView.adapter = adapter
}
}
RecyclerView Adapter:
class MyAdapter() : RecyclerView.Adapter<MyAdapter.MyViewHolder>() {
private var postList = emptyList<Post>()
class MyViewHolder(view: View) : RecyclerView.ViewHolder(view) {
val idView: TextView = view.findViewById(R.id.id_txt)
val nameView: TextView = view.findViewById(R.id.name_txt)
}
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): MyViewHolder {
return MyViewHolder(
LayoutInflater.from(parent.context).inflate(R.layout.row_layout, parent, false)
)
}
override fun onBindViewHolder(holder: MyViewHolder, position: Int) {
val currentItem = postList[position]
holder.idView.text = currentItem.id.toString()
holder.nameView.text = currentItem.name
}
override fun getItemCount(): Int = postList.size
fun setData(newList: List<Post>){
postList = newList
notifyDataSetChanged()
}
}
Post:
data class Post(
#SerializedName("id")
val id: Int,
#SerializedName("name")
val name: String
)
Try to use next class in response object:
data class PokedexResponse (
#SerializedName("pokemon")
val pokemons: List<Post>
)
interface SimpleApi {
#GET("pokedex.json")
suspend fun getCustomPosts(): Response<PokedexResponse>
}
My guess is that you missed to parse pokemon object:
{
"pokemon": [{ ... }]
}
I have two activity and each activity has recyclerview, I have nested json.I want when user tap first activity recyclerview then they goes to next activity and show the recyclerview.Better understanding please follow the json link and code.
Json Link
: https://run.mocky.io/v3/8c3f6be2-a53f-47da-838c-72e603af844d
CropData.kt
data class CropData(
#SerializedName("cropImage")
val cropImage: String,
#SerializedName("cropName")
val cropName: String,
#SerializedName("cropTime")
val cropTime: String,
#SerializedName("cropDetails")
val cropDetails: String,
#SerializedName("cropProcess")
val cropProcess: String,
#SerializedName("cropType")
val cropType: String,
#SerializedName("cropFertilizer")
val cropFertilizer: List<CropFertilizer>
)
CropFertilizer.kt
data class CropFertilizer(
#SerializedName("fertilizerName")
val fertilizerName: String,
#SerializedName("fertilizerFirst")
val fertilizerFirst: String,
#SerializedName("fertilizerSecond")
val fertilizerSecond: String,
#SerializedName("fertilizerThird")
val fertilizerThird: String
)
CropActivity.kt
class CropActivity : AppCompatActivity(), CropOnItemClickListener {
private lateinit var viewModel: CropActivityViewModel
private val cropAdapter by lazy { CropAdapter(this) }
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_crop)
val repository = Repository()
val viewModelFactory = CropActivityViewModelFactory(repository)
viewModel = ViewModelProvider(this, viewModelFactory).get(CropActivityViewModel::class.java)
viewModel.getCropData()
viewModel.cropResponse.observe(this, Observer { response ->
cropAdapter.setData(response)
Log.d("dCrop", response.toString())
})
setUpCrops()
}
private fun setUpCrops() {
crop_recyclerview.layoutManager = LinearLayoutManager(
this,
LinearLayoutManager.VERTICAL, false
)
crop_recyclerview.setHasFixedSize(true)
crop_recyclerview.adapter = cropAdapter
}
override fun onClick(item: CropData, position: Int) {
val intent = Intent(this, CropDetailsActivity::class.java)
intent.putExtra("name", item.cropName)
intent.putExtra("image", item.cropImage)
intent.putExtra("intro", item.cropDetails)
intent.putExtra("process", item.cropProcess)
intent.putExtra("type", item.cropType)
intent.putExtra("time", item.cropTime)
startActivity(intent)
}
}
CropAdapter.kt
class CropAdapter(private val cropOnItemClickListener: CropOnItemClickListener) :
RecyclerView.Adapter<CropAdapter.ViewHolder>() {
private var cropList = emptyList<CropData>()
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): ViewHolder {
val view = LayoutInflater.from(parent.context).inflate(R.layout.crop_row,parent,false)
return ViewHolder(view)
}
override fun onBindViewHolder(holder: ViewHolder, position: Int) {
holder.itemView.crop_name.text = cropList[position].cropName
holder.itemView.crop_details.text = cropList[position].cropDetails
holder.itemView.crop_time.text = cropList[position].cropTime
holder.itemView.setOnClickListener{
cropOnItemClickListener.onClick(cropList[position],position)
}
}
override fun getItemCount(): Int {
return cropList.size
}
fun setData(newList: List<CropData>){
notifyDataSetChanged()
cropList = newList
notifyDataSetChanged()
}
class ViewHolder(itemView: View): RecyclerView.ViewHolder(itemView)
}
CropDetailsActivity.kt
class CropDetailsActivity : AppCompatActivity() {
private lateinit var viewModel: CropDetailsActivityViewModel
private val fertlizerAdapter by lazy { FertilizerAdapter() }
private val cropFertilizerAdapter by lazy { FertilizerAdapter() }
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_crop_details)
val bundle:Bundle? = intent.extras
crop_details_name.text = bundle!!.getString("name")
val i: String = bundle!!.getString("intro")
crop_details_intro.text = i
Glide.with(this).load(bundle.getString("image")).into(crop_details_image);
val j: String = bundle!!.getString("process")
crop_details_process.text = j
crop_details_time.text = bundle!!.getString("time")
crop_details_type.text = bundle!!.getString("type")
val repository = Repository()
val viewModelFactory = CropDetailsActivityViewModelFactory(repository)
viewModel = ViewModelProvider(this, viewModelFactory).get(CropDetailsActivityViewModel::class.java)
viewModel.getFertilizer()
viewModel.fResponse.observe(this, Observer {
cropFertilizerAdapter.setData(it)
})
crop_details_recyclerview.layoutManager = LinearLayoutManager(
this,
LinearLayoutManager.VERTICAL, false
)
crop_details_recyclerview.setHasFixedSize(true)
crop_details_recyclerview.adapter = cropFertilizerAdapter
}
}
Better understanding see the image
[1]: https://i.stack.imgur.com/BtPqe.jpg
I want to show CropFertilizer list in CropDetailsActivity.How can i do this?
hello guys I am using a gson api with a Recyclerview and I got this error with the adapter and it says that the
expression 'myAdapter' of type 'myAdapter' cannot be invoked as a function. the function 'invoked' is not found
and when I run the code without the data it gives me this error:
lateinit property myAdapter has not been initialized
my activities and classes
private val datalist: MutableList<Sura> = mutableListOf()
private lateinit var myAdapter: MyAdapter
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_quran_a_p_i)
myAdapter = myAdapter(datalist) // here is the error
apiQuranRecyclerView.layoutManager = LinearLayoutManager(this)
apiQuranRecyclerView.addItemDecoration(DividerItemDecoration(this, OrientationHelper.VERTICAL))
apiQuranRecyclerView.adapter = myAdapter
AndroidNetworking.initialize(this)
AndroidNetworking.get("http://api.islamhouse.com/v1/mykey/quran/get-category/462298/ar/json/")
.build()
.getAsObject(Surasnames::class.java, object : ParsedRequestListener<Surasnames>{
override fun onResponse(response: Surasnames) {
datalist.addAll(response.suras)
myAdapter.notifyDataSetChanged()
}
override fun onError(anError: ANError?) {
}
})
}
my Adapter
class MyAdapter (private val datalist: MutableList<Sura>): RecyclerView.Adapter<myHolder>() {
private lateinit var context: Context
override fun onCreateViewHolder(parent: ViewGroup, p1: Int): myHolder {
context = parent.context
return myHolder(LayoutInflater.from(context).inflate(R.layout.api_quran_view, parent, false))
}
override fun getItemCount(): Int = datalist.size
override fun onBindViewHolder(holder: myHolder, position: Int) {
val data = datalist[position]
val apisuraname = holder.itemView.apiSuraNames
val surasnames = "${data.id} ${data.title}"
apisuraname.text = surasnames
holder.itemView.setOnClickListener {
Toast.makeText(context, surasnames, Toast.LENGTH_SHORT).show()
}
}
my Holder
class myHolder(itemView: View) : RecyclerView.ViewHolder(itemView) {
}
my Models
data class Sura(
#SerializedName("add_date")
val addDate: Int,
#SerializedName("api_url")
val apiUrl: String,
#SerializedName("id")
val id: Int,
#SerializedName("title")
val title: String,
#SerializedName("type")
val type: String
)
the second one
data class Surasnames(
#SerializedName("add_date")
val addDate: Int,
#SerializedName("description")
val description: String,
#SerializedName("id")
val id: Int,
#SerializedName("locales")
val locales: List<Any>,
#SerializedName("suras")
val suras: List<Sura>,
#SerializedName("title")
val title: String)
thanks in advance
You need to call the constructor. Change the line
myAdapter = myAdapter(datalist)
to
myAdapter = MyAdapter(datalist)
Trying to fetch the data from the server using Retrofit and caching it offline using Room Database.
Problem I have fetched the data from the server and inserted it into the room but could not populate it. After evaluating the expression, the LiveData list is null.
I am certain that the insertion is successful, as I went through some answers on StackOverflow which mentioned to return the list of IDs to find out if there has been an insert.
Below is my code:
User.kt
#Entity(tableName = "user_table")
data class User(
#PrimaryKey(autoGenerate = true)
val id:Long,
#Json(name = "name")
val uname:String,
val username:String,
val email:String,
#Embedded
val address: Address,
val phone:String,
val website:String,
#Embedded
val company: Company)
data class Address(
val street:String,
val suite:String,
val city:String,
val zipcode:String,
#Embedded
val geo: Geo)
data class Geo(
val lat:String,
val lng:String)
data class Company(
#Json(name = "name")
val companyName:String,
val catchPhrase:String,
val bs:String)
UserDao.kt
#Dao
interface UserDao{
#Query("select * from user_table")
fun getUserList():LiveData<List<User>>
#Insert(onConflict = OnConflictStrategy.REPLACE)
fun insertAll(userList:List<User>):List<Long>
}
UserRepository.kt
class UserRepository(private val userDao: UserDao) {
val userList: LiveData<List<User>> = userDao.getUserList()
suspend fun refreshUserList() {
withContext(Dispatchers.IO) {
val userList = UserApi.retrofitService.getUserData().await()
val list = userDao.insertAll(userList)
Log.e("list","${list.size}")
}
}
}
MainActivityViewModel.kt
class MainActivityViewModel(database:UserDao, application: Application) : AndroidViewModel(application){
private val userRepository = UserRepository(database)
val usersList = userRepository.userList
private var viewModelJob = Job()
private val coroutineScope = CoroutineScope(viewModelJob + Dispatchers.Main)
init {
getUsersList()
}
private fun getUsersList() {
coroutineScope.launch {
try{
userRepository.refreshUserList()
}catch (networkError: IOException){
Toast.makeText(getApplication(),"Failure",Toast.LENGTH_SHORT).show()
}
}
}
override fun onCleared() {
super.onCleared()
viewModelJob.cancel()
//Main View Model Destroys
}
}
UserAdapter.kt
class UserAdapter : RecyclerView.Adapter<UserAdapter.ViewHolder>(){
var userDetailsList:List<User> = emptyList()
set(value) {
field = value
notifyDataSetChanged()
}
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): ViewHolder {
return ViewHolder(UserCellLayoutBinding.inflate(
LayoutInflater.from(parent.context)
))
}
override fun getItemCount(): Int {
return userDetailsList.size
}
override fun onBindViewHolder(holder: ViewHolder, position: Int) {
val user = userDetailsList[position]
holder.bind(user)
}
class ViewHolder(private var binding: UserCellLayoutBinding) :
RecyclerView.ViewHolder(binding.root) {
fun bind(user: User){
binding.user = user
binding.executePendingBindings()
}
}
}
MainActivity.kt
class MainActivity : AppCompatActivity() {
private lateinit var binding: ActivityMainBinding
private lateinit var viewModelFactory: ViewModelFactory
private lateinit var viewModel: MainActivityViewModel
private var adapter:UserAdapter ?= null
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
binding = DataBindingUtil.setContentView(this, R.layout.activity_main)
val dataSource = UserRoomDatabase.getInstance(application).userDao
viewModelFactory = ViewModelFactory(dataSource,application)
viewModel = ViewModelProviders.of(this,viewModelFactory).get(MainActivityViewModel::class.java)
binding.lifecycleOwner = this
binding.mainActivityViewModel = viewModel
binding.executePendingBindings()
binding.userListRecyclerView.adapter = adapter
viewModel.usersList.observe(this, Observer<List<User>> {users ->
users?.apply {
adapter?.userDetailsList = users
}
})
}
}
Any help would be greatly appreciated.
Thanks in advance.
I forgot to instantiate the adapter in MainActivity.kt
adapter = UserAdapter()
binding = DataBindingUtil.setContentView(this, R.layout.activity_main)
val dataSource = UserRoomDatabase.getInstance(application).userDao
viewModelFactory = ViewModelFactory(dataSource,application)
viewModel = ViewModelProviders.of(this,viewModelFactory).get(MainActivityViewModel::class.java)
binding.lifecycleOwner = this
binding.mainActivityViewModel = viewModel
binding.executePendingBindings()
adapter = UserAdapter()
binding.userListRecyclerView.adapter = adapter
viewModel.usersList.observe(this, Observer<List<User>> {users ->
users?.apply {
adapter?.userDetailsList = users
}
})