I'm developing an app to store TV shows informations. The use can add shows and then view its collection. I want, when adding a show, to be able to also add seasons to it, and several if need be.
I have Show and Season models, and I've created an AddShowActivity with its add_show_activity layout. I've started using Android Studio not long ago so maybe this is not optimal, but I thought of using a RecyclerView inside of my layout, and then recycle an item_add_season layout in order to add as many seasons as I want while creating a show.
However, this has caused several problems to me, to which I couldn't find any answer and am currently lost as to what to do. I've put an Add Season button in my add_show_activity, which is supposed to add a new item_add_season to my RecyclerView, however I didn't know how I should go about doing that. And even if I still haven't tried it, I'm wondering how I'll be able to retrieve my data from outside of my Adapter.
So I've been wondering if it was possible to use a RecyclerView like that in order to add several seasons to my form ? And if not, how should I go about doing that ?
Below are my AddShowActivity and my AddSeasonAdapter (the recyclerview adapter).
class AddShowActivity : AppCompatActivity() {
private lateinit var editTextName: EditText
private lateinit var editTextNote: EditText
private lateinit var confirmButton: Button
private lateinit var addSeasonButton: Button
private lateinit var seasonsRecyclerView: RecyclerView
#SuppressLint("NewApi")
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_add_show)
editTextName = findViewById(R.id.name_input)
editTextNote = findViewById(R.id.note_input)
seasonsRecyclerView = findViewById(R.id.seasons_recycler_view)
seasonsRecyclerView.adapter = AddSeasonAdapter(this, 0, R.layout.item_add_season)
seasonsRecyclerView.layoutManager = LinearLayoutManager(this)
confirmButton = findViewById(R.id.confirm_button)
confirmButton.setOnClickListener{
sendForm()
}
addSeasonButton = findViewById(R.id.add_season_button)
addSeasonButton.setOnClickListener {
// Add a season to the RecyclerView and update its seasonsCount
}
}
#SuppressLint("NewApi")
private fun sendForm(){
val repo = ShowRepository()
val showName = editTextName.text.toString()
val showNote = parseInt(editTextNote.text.toString())
val seasonsList = arrayListOf<SeasonModel>() // Get info from seasons adapter and create seasons list
val show = ShowModel(UUID.randomUUID().toString(), showName, showNote, seasonsList)
repo.insertShow(show)
this.finish()
}
}
class AddSeasonAdapter(val context: AddShowActivity, private var seasonsCount: Int, private val layoutId: Int) : RecyclerView.Adapter<AddSeasonAdapter.ViewHolder>() {
class ViewHolder(view: View) : RecyclerView.ViewHolder(view){
}
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): ViewHolder {
val view = LayoutInflater.from(parent.context).inflate(layoutId, parent, false)
return ViewHolder(view)
}
#SuppressLint("NewApi")
override fun onBindViewHolder(holder: ViewHolder, position: Int) {
}
override fun getItemCount(): Int = seasonsCount
}
I've found a YouTube video explaining exactly how to do it (this one for those who wanna see it).
So basically, the solution is not to use a RecyclerView but instead a LinearLayout in which the seasons are added when clicking on the 'Add season' button. This is quite easy to do, as the only thing to do is to inflate the layout, here my item_add_season, and then add it to the LinearLayout.
So like that:
// The LinearLayout in which items are added
val seasonsList = findViewById<LinearLayout>(R.id.seasons_list)
addSeasonButton.setOnClickListener {
val seasonView: View = layoutInflater.inflate(R.layout.item_add_season, null, false)
// Initialize the seasons items components
val seasonNumber = seasonView.findViewById<EditText>(R.id.season_number_input)
val seasonNote = seasonView.findViewById<EditText>(R.id.season_note_input)
val imageClose = seasonView.findViewById<ImageView>(R.id.image_close)
imageClose.setOnClickListener {
seasonsList.removeView(seasonView)
}
// Add the add_season_layout to the linearLayout
seasonsList.addView(seasonView)
}
Related
Recyclerview contains a photo and some text. Normal use case is that when the cardview is clicked the photo is selected. However, user might want to delete the photo from the list. There is an icon in the cardview (btnDelete) that can be clicked to delete a photo based on a selectClickListener in the adapter. The correct item is deleted from the database table. If the recyclerView is reloaded the correct photos are included. However, when the user is in the recyclerView and clicks a delete icon the clicked picture stays visible but the bottom cardview on the list disappears. This happens whether one card is "deleted" or numerous cards are "deleted". The bottom card is always deleted.
RecyclerView is populated from sqlite.
Regardless if removeAt is used the bottom cardview is removed when the delete key is clicked.
Tried numerous alternatives including removeAt, notifyItemRemoved, notifyItemRangeChanged. Nothing worked. Some options would reshuffle the cards so that duplicates show, deleted cards come back, etc. Wondering if it is the GlobalScope throwing everything off?
class PhotoAdapter constructor(
viewModel: TheViewModel,
val clickListener: (DBClasses.photos) -> Unit
): RecyclerView.Adapter<PhotoAdapter.CardViewHolder>() {
lateinit private var idPhotoID: TextView
lateinit private var idUploaded: TextView
lateinit private var idStatus: TextView
lateinit private var idPic: ImageView
lateinit private var idDelete: ImageView
val vh = viewModel
var data = mutableListOf<DBClasses.photos>()
set(value) {
field = value
notifyDataSetChanged()
}
inner class CardViewHolder (val binding: PhotoViewBinding) : RecyclerView.ViewHolder(binding.root) {
fun bind(photo: DBClasses.photos, clickListener: (DBClasses.photos) -> Unit) {
itemView.setOnClickListener { clickListener(photo) }
binding.btnDelete.setOnClickListener(){
removeItem(bindingAdapterPosition, vh)
data.removeAt(bindingAdapterPosition)
notifyDataSetChanged()
}
}
}
override fun getItemCount() = data.size
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): CardViewHolder {
val binding = PhotoViewBinding.inflate(LayoutInflater.from(parent.context), parent, false)
idPhotoID = binding.photoId
idUploaded = binding.tvUploaded
idStatus = binding.tvStatus
idPic = binding.imageView
idDelete = binding.btnDelete
return CardViewHolder(binding)
}
override fun getItemId(position: Int): Long {
return position.toLong()
}
override fun getItemViewType(position: Int): Int {
return position
}
override fun onBindViewHolder(holder: CardViewHolder, position: Int) {
var gpath: String = "/storage/self/primary/Android/data/com.prod.TheAppName/files/Pictures"
val parentDirectory = path
val dirFileObj = File(parentDirectory)
val item = data[position]
Picasso.get()
.load(File(dirFileObj.toString() + File.separator + item.photo_name))
.resize(225,150)
.centerCrop()
.into(idPic)
idPhotoID.text = item.photo_id.toString()
val rawdate: DateTimeFormatter = DateTimeFormatter.ofPattern("yyyy-MM-d HH:mm:ss.SSS", Locale.ENGLISH)
val actualdate = LocalDate.parse(item.upload_date, rawdate).toString()
idUploaded.text = actual-date
idStatus.text = item.status
holder.bind(data[position],clickListener)
}
fun removeItem(position: Int, viewModel: TheViewModel) {
val positionID = data[position].photo_id
GlobalScope.launch () {
viewModel.inactivateRecyclerViewPhotos(positionID)
}
}
}
I am building an Android app with Kotlin and decided to replace the calls to findViewById and use binding. It all works fine but specifically, when I change an Adapter for a RecyclerView it breaks the item layout.
Original code with findViewById:
class WeightListAdapter(val weights: List<WeightWithPictures>, val onWeightItemClickListener: OnWeightItemClickListener) : RecyclerView.Adapter<WeightListAdapter.WeightHolder>() {
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): WeightListAdapter.WeightHolder {
val view = LayoutInflater.from(parent.context).inflate(R.layout.list_item_weight, parent, false)
return WeightHolder(view)
}
override fun onBindViewHolder(holder: WeightListAdapter.WeightHolder, position: Int) {
val weightWithPictures = weights[position]
holder.bind(weightWithPictures)
}
override fun getItemCount() = weights.size
inner class WeightHolder(itemView: View) : RecyclerView.ViewHolder(itemView), View.OnClickListener {
private lateinit var weight: Weight
private val weightValueView: TextView = this.itemView.findViewById(R.id.weightValue)
private val weightDateView: TextView = this.itemView.findViewById(R.id.weightDate)
private val weightImageView: ImageView = this.itemView.findViewById(R.id.weightImage) as ImageView
And this is the layout:
But then whenever I use binding:
class WeightListAdapter(val weights: List<WeightWithPictures>, val onWeightItemClickListener: OnWeightItemClickListener) : RecyclerView.Adapter<WeightListAdapter.WeightHolder>() {
private var _binding: ListItemWeightBinding? = null
private val binding get() = _binding!!
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): WeightListAdapter.WeightHolder {
_binding = ListItemWeightBinding.inflate(LayoutInflater.from(parent.context))
val view = binding.root
return WeightHolder(view)
}
override fun onBindViewHolder(holder: WeightListAdapter.WeightHolder, position: Int) {
val weightWithPictures = weights[position]
holder.bind(weightWithPictures)
}
override fun getItemCount() = weights.size
inner class WeightHolder(itemView: View) : RecyclerView.ViewHolder(itemView), View.OnClickListener {
private lateinit var weight: Weight
private val weightValueView: TextView = binding.weightValue
private val weightDateView: TextView = binding.weightDate
private val weightImageView: ImageView = binding.weightImage
The layout breaks:
Any ideas about what am I doing wrong here? Is it a bug?
P.S - For now, I am just adding the annotation to ignore bindings as documented here for the item view but I would really like to understand what's wrong.
Your binding needs to be inflated in the context of its parent so its root view's layout params will take effect:
binding = ListItemWeightBinding.inflate(LayoutInflater.from(parent.context), parent, false)
I think it will also give you problems that you are creating a binding property for the Adapter if you try to use it long term. Each ViewHolder holds a distinct view with a distinct binding instance. It's working now because you use it only for the ViewHolder instantiation immediately after setting each instance. But if that's all your intent is, you should just pass the binding to the constructor of your ViewHolder and omit the adapter's property.
By the way, this is the sort of pattern I use for ViewHolders. Less code. Note, it doesn't have to be an inner class.
class WeightHolder(binding: ListItemWeightBinding) : RecyclerView.ViewHolder(binding.root), View.OnClickListener {
fun bind(item: WeightWithPictures) {
with (binding) {
// set data for views here
}
}
}
I agree with #Tenfour04, using the same instance of binding is wrong but I believe the root cause of your issue is with the binding logic. with binding, the data is bound to bind with the view but not immediately. So your view gets inflated but since the binding happens at a later stage, scheduled to happen in near future, the item_view width is shrunk.
So try the following,
// oncreate view logic
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): WeightListAdapter.WeightHolder {
val binding = ListItemWeightBinding.inflate(LayoutInflater.from(parent.context), parent, false)
return WeightHolder(binding)
}
// onBindViewHolder logic remains the same
// this remains same as suggested by #Tenfour04 but a change in the bind function
class WeightHolder(binding: ListItemWeightBinding) : RecyclerView.ViewHolder(binding.root), View.OnClickListener {
fun bind(item: WeightWithPictures) {
with (binding) {
// set data for views using databindig
customVariable = item
executePendingBindings() // this is important
}
}
}
// define the customvariable in your `item_list_view.xml`
<variable
name="customVariable"
type="packagename.WeightWithPictures" />
executePendingBindings() is the way we force the binding to happen right away and not to schedule it later
Edit:
This answer is from Databinding perspective and not ViewBinding
I have a RecyclerView which was build using an Arraylist. That Arraylist consists of User defined objects named ListItem.
Each recyclerview has a card view. Each CardView holds each ListItem.
I have removed one CardView from that RecyclerView.
When I rotate the screen , A new Activity is created which results in showing the old data. But I want the recyclerview to hold only updated list and should retain the scrolled position.
ListItem class :
class ListItem(var title: String, var info: String, val imageResource: Int) {
}
MainActivity class :
class MainActivity : AppCompatActivity() {
private lateinit var mSportsData: ArrayList<ListItem>
private lateinit var mAdapter: MyAdapter
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
val gridColumnCount = resources.getInteger(R.integer.grid_column_count)
recycler_view.layoutManager = GridLayoutManager(this,gridColumnCount)
mSportsData = ArrayList()
recycler_view.setHasFixedSize(true)
initializeData()
recycler_view.adapter = mAdapter
var swipeDirs = 0
if (gridColumnCount <= 1) {
swipeDirs = ItemTouchHelper.LEFT or ItemTouchHelper.RIGHT
}
val helper = ItemTouchHelper(object : ItemTouchHelper.SimpleCallback(ItemTouchHelper.LEFT or ItemTouchHelper.RIGHT or ItemTouchHelper.UP or ItemTouchHelper.DOWN,swipeDirs) {
override fun onMove(recyclerView: RecyclerView, viewHolder: RecyclerView.ViewHolder, target: RecyclerView.ViewHolder): Boolean {
val from = viewHolder.adapterPosition
val to = target.adapterPosition
Collections.swap(mSportsData,from,to)
mAdapter.notifyItemMoved(from,to)
return true
}
override fun onSwiped(viewHolder: RecyclerView.ViewHolder, direction: Int) {
mSportsData.removeAt(viewHolder.adapterPosition)
mAdapter.notifyItemRemoved(viewHolder.adapterPosition)
}
})
helper.attachToRecyclerView(recycler_view)
}
private fun initializeData() {
val sportsList : Array<String> = resources.getStringArray(R.array.sports_titles)
Log.d("Printing","$sportsList")
val sportsInfo : Array<String> = resources.getStringArray(R.array.sports_info)
val sportsImageResources : TypedArray = resources.obtainTypedArray(R.array.sports_images)
mSportsData.clear()
for (i in sportsList.indices-1) {
Log.d("Printing","${sportsList[i]},${sportsInfo[i]},${sportsImageResources.getResourceId(i,0)}")
mSportsData.add(ListItem(sportsList[i], sportsInfo[i], sportsImageResources.getResourceId(i, 0)))
}
sportsImageResources.recycle()
mAdapter = MyAdapter(mSportsData,this)
mAdapter.notifyDataSetChanged()
}
fun resetSports(view: View) {
initializeData()
}
}
MyAdapter class :
class MyAdapter(var mSportsData: ArrayList<ListItem>, var context: Context) : RecyclerView.Adapter<MyAdapter.ViewHolder>() {
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): ViewHolder {
return ViewHolder(LayoutInflater.from(context).inflate(R.layout.wordlist_item,parent,false))
}
override fun getItemCount() = mSportsData.size
override fun onBindViewHolder(holder: ViewHolder, position: Int) {
val listItem = mSportsData.get(position)
holder.bindTo(listItem)
}
inner class ViewHolder(itemView: View) : RecyclerView.ViewHolder(itemView), View.OnClickListener {
init {
itemView.setOnClickListener(this)
}
override fun onClick(view: View) {
val currentSport = mSportsData.get(adapterPosition)
val detailIntent = Intent(context, DetailActivity::class.java)
detailIntent.putExtra("title", currentSport.title)
detailIntent.putExtra("image_resource", currentSport.imageResource)
context.startActivity(detailIntent)
}
fun bindTo(currentSport : ListItem){
itemView.heading_textview.setText(currentSport.title)
itemView.description_textview.setText(currentSport.info)
Glide.with(context).load(currentSport.imageResource).into(itemView.image_view)
}
}
}
You can restrict activity restarting in your Manifest if you have same layout for Portrait and Landscape mode.
Add this to your activity in the manifest.
<activity android:name=".activity.YourActivity"
android:label="#string/app_name"
android:configChanges="orientation|screenSize"/>
If you don't want to restrict screen orientation changes, then you can use OnSaveInstanceState method to save your older data when orientation changed. Whatever data you save via this method you will receive it in your OnCreate Method in bundle. Here is the helping link. So here as you have ArrayList of your own class type you also need to use Serializable or Parcelable to put your ArrayList in your Bundle.
Except these making ArrayList as public static is always a solution, But its not a good solution in Object Oriented paratime. It can also give you NullPointerException or loss of data, in case of low memory conditions.
It looks like initializeData is called twice since onCreate is called again on orientation change, you could use some boolean to check if data has been already initialized then skip initializing
What you are doing is you are deleting the values that are passed down to the recyclerview but when the orientation changes the recyclerview reloads from activity and the original data from activity is passed down again and nothing changes, so if you want to save the changes in recyclerview you have to change the original data in the activity so that if the view reloads the data is the same.
I think u initialize adapter in oncreate method in which the whole adapter will be recreated and all datas is also newly created when configuration changes. Because u init data in oncreate method. Try something globally maintain the list and also delete the item in the list in activity when u delete in adapter also. Or try something like view model architecture
Use MVVM pattern in the project. It will manage the orientation state.
MVVM RecyclerView example:
https://medium.com/#Varnit/android-data-binding-with-recycler-views-and-mvvm-a-clean-coding-approach-c5eaf3cf3d72
I'm having a problem when call the notifyItemRangeInserted of the adapter. When I call this method, nothing happens, simple as that. I've tried to set some println() in the ViewHolderAdapter, but he isn't called, so I can't view the prints.
I've tried all of the "notify" commands of the adapter, and none of these work. Simply nothing happens.
That's my MainActivity. All the objects and arrays I've tested, all of them are working like a charm. I can't understand why the notify doesn't work.
class MainActivity:AppCompatActivity(){
//Declarations of the variables
var pageNumber = 1
var limitPerPage = 5
lateinit var product: Product
var productList = ArrayList<EachProduct>()
var myAdapter =ViewHolderAdapter(productList, productList.size)
override fun onCreate(savedInstanceState:Bundle?){
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
recyclerView.layoutManager = LinearLayoutManager(this#MainActivity)
recyclerView.adapter = myAdapter
The code to add items on the list and notify the ViewHolderAdapter is
//update the product list
fun updateProductList(product:Product){
for(i in 0 until 5 step 1){
productList.add(product.produtos[i])
}
showData(productList,pageNumber*limitPerPage)//then notify
}
fun showData(productList:List<EachProduct>,productsListSize:Int){
myAdapter.notifyItemRangeInserted(0,productList.size)
}
That's my ViewHolderAdapter class
class ViewHolderAdapter(private var products: List<EachProduct>, private val productsListSize: Int): RecyclerView.Adapter<ViewHolderAdapter.ViewHolder>() {
override fun onCreateViewHolder(parent:ViewGroup,viewType:Int): ViewHolder {
val view = LayoutInflater.from(parent.context).inflate(R.layout.recyclerview_layout, parent, false)
returnViewHolder(view)
}
override fun getItemCount() = productsListSize
override fun onBindViewHolder(holder: ViewHolder, position: Int) {
holder.productName.text=products[position].nome
Picasso.get().load(products[position].fabricante.img).into((holder.productLogo))
}
class ViewHolder(itemView: View): RecyclerView.ViewHolder(itemView) {
val productName:TextView=itemView.ProductName
var productLogo:ImageView=itemView.ProductLogo
}
}
I expect the ViewHolderAdapter to be called, but this is not occurring. Why is that happens? I can't understand. I'll be very grateful if someone could help me.
Because initial value of the variable productsListSize is zero. Remove it from the constructor and change adapter like this:
class ViewHolderAdapter(private var products: List<EachProduct>): RecyclerView.Adapter<ViewHolderAdapter.ViewHolder>() {
override fun getItemCount() = products.size
}
A reason can be that the initial size of the item list you want to show is 0 and the recycler view height is set to wrap content. At the moment, for this case I see 2 options:
Keep wrap content for recycler view and make sure the initial list size > 0.
Set the height of the recycler view to match_parent or a fixed size and notifyItemRangeInserted will work without issues.
I have a nested recyclerview which should look like in the .
I implemented it according to this helpful site.
The problem is, that I sometimes have a user with hundreds of items and in that case, it takes half a minute to open the activity.
I have a room database in the backend with two linked tables with foreign keys (users and items) and I select all users to get a user/item list where the items are a list in the user-table.
class userWithItems: (id: Int, name: String, ... ,List)
and I create the inner recycler view with the List of items in the adapter.
Would it be better to make one List UserItems (userid:Int, username:String, ... itemid:Int, itemList) and group them for the outer rv.
Or is there a possibility to get rid of the nested rv and make the design with just one recyclerview-list?
Or is there another solution to make the nested recyclerview work even if there are many items for a user?
code for the adapters:
// Code in Activity: (oncreate)
val recyclerView = findViewById<RecyclerView>(R.id.rv_users)
val adapter = UserAdapter(this)
recyclerView.adapter = adapter
recyclerView.layoutManager = LinearLayoutManager(this)
mainViewModel = ViewModelProviders.of(this, PassIntViewModelFactory(this.application, online_id)).get(MainViewModel::class.java!!)
mainViewModel.userList.observe(this, Observer {
it?.let {
adapter.setUserList(it)
}
})
data class UsersWithItems(
val id:Int, val username: String, val address, // fields from user table
val items: List<Items> // list of items for current user
)
data class Items (
val id: Int, val itemtext: String, val itemlocation: String, val image: String // ...
)
// UserAdapter (outside)
class UserAdapter internal constructor(
context: Context
) : RecyclerView.Adapter() {
private val inflater: LayoutInflater = LayoutInflater.from(context)
private var userList = emptyList<UsersWithItems>()
inner class MyViewHolder(itemView: View) : RecyclerView.ViewHolder(itemView) {
val username: TextView = itemView.findViewById(R.id.user_name)
val num_pos: TextView = itemView.findViewById(R.id.user_num_pos)
val address: TextView = itemView.findViewById(R.id.user_addr)
val rv:RecyclerView = itemView.findViewById(R.id.rv_user_items)
}
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): MyViewHolder {
val myItemView = inflater.inflate(R.layout.rv_row_user, parent, false)
return MyViewHolder(myItemView)
}
override fun onBindViewHolder(holder: MyViewHolder, position: Int) {
val current = userList[position]
holder.username.text="${current.user?.username}"
holder.num_pos.text="${current.items?.size}"
holder.address.text = "${current.user?.address}"
val adapter = UserItemAdapter(holder.rv.context)
adapter.setItems(current.items!!)
holder.rv.adapter = adapter
holder.rv.layoutManager = LinearLayoutManager(holder.rv.context,LinearLayout.VERTICAL,false)
}
internal fun setUserList(userList: List<UsersWithItems>){
this.userList=userList
notifyDataSetChanged()
}
override fun getItemCount() = userList.size
}
class UserItemAdapter internal constructor(
context: Context
) : RecyclerView.Adapter() {
private val inflater: LayoutInflater = LayoutInflater.from(context)
private var itemList = emptyList<Items>()
inner class MyViewHolder(itemView: View) : RecyclerView.ViewHolder(itemView) {
val itemtext: TextView = itemView.findViewById(R.id.item_text)
val itemlocation:TextView = itemView.findViewById(R.id.item_location)
val image: ImageView = itemView.findViewById(R.id.item_image)
}
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): MyViewHolder {
val myItemView = inflater.inflate(R.layout.rv_row_user_items, parent, false)
return MyViewHolder(myItemView)
}
override fun onBindViewHolder(holder: MyViewHolder, position: Int) {
val current = itemList[position]
holder.itemtext.text="${current.itemtext}"
holder.itemlocation.text = current.itemlocation
if (current.image.length>0) {
val image = Base64.decode(current.image, 0)
val bitmap = BitmapFactory.decodeByteArray(image, 0, image.size)
holder.image.setImageBitmap(bitmap)
}
}
internal fun setItems(items: List<Items>){
this.itemList=items
notifyDataSetChanged()
}
override fun getItemCount() = itemList.size
}
E. Reuter i have been through this situation the thing is the approach is quite correct by using nested Recycler View. Your code seems to be good. but the queries which you are using to query database. I think you should use queries in Background or on the other threas and show result as you get them instead of querying it from OnCreate or from main thread. Because getting this many items in one go can possibly create lag to activity and decreasing performance. try this out if you have not yet and let me know. What happens. Thanks...
I am editing my answer. the other thing you could do is if you have more than certain amount of items then instead of getting them at the first you should use some thing like pagination to load certain amount of items at once to avoid this lag.
Here i am attaching the code to query certain amount of data per load....
SApp.database!!.resultDao().loadAllUsersByPage(5, 10)
#Query("SELECT * FROM Result LIMIT :limit OFFSET :offset")
fun loadAllUsersByPage(limit: Int, offset: Int): List<Result>
Thank you very much for your answer. I think that paging is really a good approach. But I cannot add the pageing directly since I am getting my data from a roomdatabase like this:
#Query(SELECT * FROM users)
fun getData(): LiveData<List<userWithItems>>
and the actual items are added by room because of a relation between user and items I will have to change this behavior.
I will try something like
#Query(SELECT * FROM users)
fun getUserData(): LiveData<List<Users>>
and then try to add an LiveData observer in the outer recyclerview to get the items in a separate query which uses paging.
I solved the problem. When I thought about pagination it came into my mind that the problem could be that the inner recyclerview has a height of wrap_content and so it needs to build all of the items and makes the rv useless. When I make the height of the inner rv 250dp, it works quite even with 2000 items.
So now I just have to figure out a way to always find the optimal height for the inner rv and solve the scrolling problem but the original problem is solved.
Special thanks to Aman B!