RecyclerView keeps scrolling
I am making a Media Library app. When I use the recyclerview list it scrolls over the same
items again and again. It does not stop when it reaches the bottom of the file list.
class MediaListAdapter(val mediaList: ArrayList<Media>): RecyclerView.Adapter<MediaListAdapter.MediaViewHolder>(){
private var context: Context? = null
fun updateMediaList(newMediaList: List<Media>){
mediaList.clear()
mediaList.addAll(newMediaList)
notifyDataSetChanged()
}
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): MediaViewHolder {
context = parent.context
val inflater = LayoutInflater.from(parent.context)
val view = DataBindingUtil.inflate<ItemMediaBinding>(inflater, R.layout.item_media, parent, false)
return MediaViewHolder(view)
}
override fun onBindViewHolder(holder: MediaViewHolder, position: Int) {
holder.view.btnPlayVideo.visibility = View.INVISIBLE
holder.view.mediaItem = mediaList[position]
if(mediaList[position].mediaUrl.contains(".mp4")){
holder.view.btnPlayVideo.visibility = View.VISIBLE
holder.view.btnPlayVideo.setOnClickListener {
context!!.startActivity(Intent(context, VideoViewActivity::class.java).putExtra("videoUrl", mediaList[position].mediaUrl))
}
}
}
override fun getItemCount():Int {
return mediaList.size
}
class MediaViewHolder(var view: ItemMediaBinding) : RecyclerView.ViewHolder(view.root)
}
That is my Adapter class.
The media information is being pulled from a database containing the image urls and other information related to the information.
I have compared my code to a similar solution that works how I want and can't find any reason for the bug.
val media = MutableLiveData<List<Media>>()
val loading = MutableLiveData<Boolean>()
private val mediaList = ArrayList<String>()
fun fetchFromDatabase() {
loading.value = true
loadImages()
launch {
storeMedia(mediaList)
val media = MediaDatabase(getApplication()).mediaDao().getAllMedia()
mediaRetrieved(media)
}
}
private fun mediaRetrieved(mediaList: List<Media>) {
media.value = mediaList
loading.value = false
}
private fun storeMedia(list: List<String>) {
var found = false
launch {
val dao = MediaDatabase(getApplication()).mediaDao().getAllMedia()
for(item in list){
found = false
for(media in dao){
if(item == media.mediaLocation){
found = true
break
}
}
if(!found){
val media = Media(mediaUrl = item)
MediaDatabase(getApplication()).mediaDao().insert(media)
}
}
}
}
That is the code from the viewholder were I am adding data to the recyclerview adapter
Check the size of items that are available is your db/api from wherever you are retrieving media information(May be you are receiving the repeated data).
Related
I have one RecyclerView, and if I click one item of it, I want make Data of RecyclerView change.
companion object {
var regionData: MutableLiveData<List<String>> = MutableLiveData()
var smallRegionScreen : Boolean = false
}
So I use MutableLiveData to make Data mutable and keep being observed.
adapter = regionData.value?.let { RegionAdapter(this, it, smallRegionScreen) }!!
I pass regionData.value as Data of Adapter, whose type will be List. And smallRegionScreen is Boolean value.
Since first click of item and second click of item in RecyclerView's taken action will be different, so I differentiate it by this value.
regionDB.get()
.addOnSuccessListener { documents ->
for (document in documents) {
var newArray = ArrayList<String>()
Log.d("리지온1", "$document")
for ((k, v) in document.data) {
regionData.value.add(v.String)
Log.d("리지온", "${regionData.value}")
}
}
adapter.notifyDataSetChanged()
}
binding.regionRecycler.adapter=adapter
binding.regionRecycler.layoutManager= LinearLayoutManager(this)
}
As here, I add item to regionData.value.
But it shows empty Array.
What is problem here?
And My Adapter is below, my process is okay?
class RegionAdapter(private var context: Context, private var regionData: List<String>, private var smallRegionScreen: Boolean): RecyclerView.Adapter<RegionAdapter.RegionViewHolder>() {
var userDB = Firebase.firestore.collection("users")
var userId = Firebase.auth.currentUser?.uid
companion object {
var REGION_RECYCLER_CLICKED = "com.chungchunon.chunchunon_android.REGION_RECYCLER_CLICKED"
}
inner class RegionViewHolder(ItemView: View) : RecyclerView.ViewHolder(ItemView) {
val regionView: TextView = itemView.findViewById(R.id.regionSelectText)
fun bind (position: Int) {
regionView.text = regionData[position]
}
}
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): RegionViewHolder {
val view = LayoutInflater.from(parent.context)
.inflate(R.layout.item_region, parent, false)
return RegionViewHolder(view)
}
override fun onBindViewHolder(holder: RegionViewHolder, position: Int) {
holder.bind(position)
holder.itemView.setOnClickListener { view ->
if(!smallRegionScreen) {
var selectedRegion = regionData[position]
var regionSet = hashMapOf(
"region" to selectedRegion
)
userDB.document("$userId").set(regionSet)
var regionDB = Firebase.firestore.collection("region")
regionDB
.document("4ggk4cR82mz46CjrLg60")
.collection(selectedRegion.toString())
.get()
.addOnSuccessListener { documents ->
for (document in documents) {
for ((k, v) in document.data) {
regionData.plus(v.toString())
}
}
smallRegionScreen = true
}
} else {
var selectedSmallRegion = regionData[position]
var regionSet = hashMapOf(
"smallRegion" to selectedSmallRegion
)
userDB.document("$userId").set(regionSet)
}
}
}
override fun getItemCount(): Int {
return regionData.size
}
}
If you want to add data to your MutableLiveData:
val regionDataList = regionData.value
val templateList = mutableListOf<String>()
regionDataList?.forEach { data ->
templateList.add(data)
}
templateList.add(v.String)
regionData.value = templateList
you can add data in the list like this :-
regionData.value.add(v.toString())
I wanted to add a SearchView to my recyclerview. I wanted it to be at the top and scrollable with the items. To achieve this, I created separate adapter for my header and it contains the Searchview as well. Then I used a ConcatAdapter to combine this header adapter with the contents below it.
Initially I want all the items to be visible under the SearchView from _onBoardingState which is a MutableStateFlow and when user searches for a tag then the results for it get added to _onSearch which is also a MutableStateFlow.
I have this MutableStateFlow, _onBoardingState inside my ViewModel that gets the value from Firestore in the init of ViewModel. The number of results is less (~ 20) so there is no pagination implemented and all items get loaded at once.
Now, whenever user wants to search an item by a tag, the SearchView returns a Flow of the typed value and also a Flow that updates about if the SearchView is still open or closed. I used these extension functions for this:
fun SearchView.getQueryTextChangeStateFlow(onSubmit: ()-> Unit): StateFlow<String> {
val query = MutableStateFlow("")
setOnQueryTextListener(object : SearchView.OnQueryTextListener {
override fun onQueryTextSubmit(query: String?): Boolean {
onSubmit()
return true
}
override fun onQueryTextChange(newText: String): Boolean {
query.value = newText
return true
}
})
return query
}
fun SearchView.getActiveStateFlow(): StateFlow<Boolean> {
val isOpen = MutableStateFlow(false)
setOnSearchClickListener {
isOpen.value = true
}
setOnCloseListener {
isOpen.value = false
false
}
return isOpen
}
Inside my ViewModel I have
...
private val _onBoardingState: MutableStateFlow<Model?> = MutableStateFlow(null)
private val _onSearch: MutableStateFlow<Model?> = MutableStateFlow(null)
private val _isActive: MutableStateFlow<Boolean> = MutableStateFlow(false)
fun toggleSearchViewState(isActive: Boolean) {
_isActive.value = isActive
}
val cuurentFlow: Flow<Model?> =
_isActive.flatMapLatest { isActive ->
if (isActive) {
_onSearch
} else {
_onBoardingState
}
}
...
Now the issue here is, whenever the recyclerview is scrolled down, the SearchView gets recycled and hence the setOnCloseListener gets called for it. This causes the _isActive value to be set to false by the Header's Adapter so the value of cuurentFlow gets toggled which should not be happening.
I thought of a solution as to set the setOnCloseListener of SearchView inside the header adapter's onViewRecycled() to null, but this didn't help. Below is code for my Header Adapter as well if needed.
class OnBoardingHeaderAdapter(
private val context: Context,
) : RecyclerView.Adapter<OnBoardingHeaderAdapter.HeaderViewHolder>() {
private var queryTextListener: ((StateFlow<String>) -> Unit)? = null
private var searchViewListener: ((StateFlow<Boolean>) -> Unit)? = null
inner class HeaderViewHolder(binding: OnboardingHeaderItemBinding) :
RecyclerView.ViewHolder(binding.root) {
private val root = binding.headerRoot
val search = binding.search
fun bind(headerMetaData: HeaderMetaData) {
root.visibility =
if (headerMetaData.shouldShow)
View.VISIBLE
else
View.GONE
val searchEditText: EditText =
search.findViewById(androidx.appcompat.R.id.search_src_text)
searchEditText.setHintTextColor(context.resources.getColor(R.color.white))
searchEditText.setTextColor(context.resources.getColor(R.color.white))
}
}
fun setQueryTextListener(listener: (StateFlow<String>) -> Unit) {
this.queryTextListener = listener
}
fun setSearchViewListener(listener: (StateFlow<Boolean>) -> Unit) {
this.searchViewListener = listener
}
private val RECYCLER_COMPARATOR = object : DiffUtil.ItemCallback<HeaderMetaData>() {
override fun areItemsTheSame(oldItem: HeaderMetaData, newItem: HeaderMetaData) =
oldItem.id == newItem.id
override fun areContentsTheSame(oldItem: HeaderMetaData, newItem: HeaderMetaData) =
oldItem == newItem
}
val headerDiffer = AsyncListDiffer(this, RECYCLER_COMPARATOR)
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): HeaderViewHolder {
val binding = OnboardingHeaderItemBinding.inflate(
LayoutInflater.from(parent.context), parent, false
)
return HeaderViewHolder(binding)
}
override fun onBindViewHolder(holder: HeaderViewHolder, position: Int) {
//holder.setIsRecyclable(false)
if (position < 1) {
val header = headerDiffer.currentList[position]
holder.bind(header)
}
queryTextListener?.let {
it(holder.search.getQueryTextChangeStateFlow() {
val imm = context.getSystemService(Activity.INPUT_METHOD_SERVICE) as InputMethodManager
val view: View = holder.search
imm.hideSoftInputFromWindow(view.windowToken,0)
})
}
searchViewListener?.let {
it(holder.search.getActiveStateFlow())
}
}
override fun getItemCount(): Int = headerDiffer.currentList.size
override fun onViewRecycled(holder: HeaderViewHolder) {
super.onViewRecycled(holder)
holder.search.setOnCloseListener(null)
}
}
I wanted to know what is the best approach to solve this issue, I think even if i use a recyclerview with multiple view types here for the header then still the recycling issue will be there.
I have an app which uses Room Database to show data in recycleview. It works fine when i load data seperately from different tables. But i want to show data from both tables in a single recycleview with multiple viewtypes, i know how to combine tables in room but it's not working. I get empty cards in recycleview when i load the data. Here is what i have tried so far.
My Adapter Class
class CategoriesAdapter : RecyclerView.Adapter<RecyclerView.ViewHolder>() {
companion object {
private const val TYPE_CATEGORIES = 0
private const val TYPE_ARTICLES = 1
}
private val items: MutableList<Any> by lazy {
ArrayList<Any>()
}
fun setItems(list: List<Any>) {
items.addAll(list)
notifyDataSetChanged()
}
override fun getItemViewType(position: Int): Int {
return if (items[position] is Categories) TYPE_CATEGORIES else TYPE_ARTICLES
}
override fun onCreateViewHolder(viewGroup: ViewGroup, viewType: Int): RecyclerView.ViewHolder {
return when (viewType) {
TYPE_CATEGORIES -> CategoriesViewHolder.create(viewGroup)
else -> ArticlesViewHolder.create(viewGroup)
}
}
override fun onBindViewHolder(holder: RecyclerView.ViewHolder, position: Int) {
when (holder) {
is CategoriesViewHolder -> {
if (items[position] is Categories)
holder.bind(items[position] as Categories)
}
is ArticlesViewHolder -> {
if (items[position] is Articles)
holder.bind(items[position] as Articles)
}
}
}
override fun getItemCount(): Int {
return items.size
}
}
class CategoriesViewHolder (parent: View) : RecyclerView.ViewHolder(parent) {
val textView: TextView = parent.findViewById(R.id.categories_textView)
fun bind(category: Categories) {
textView.text = category.categoryName
}
companion object {
fun create(parent: ViewGroup): CategoriesViewHolder {
return CategoriesViewHolder(LayoutInflater.from(parent.context).inflate(R.layout.categories_item_layout, parent, false))
}
}
}
class ArticlesViewHolder (parent: View) : RecyclerView.ViewHolder(parent) {
val textView: TextView = parent.findViewById(R.id.titleText)
fun bind(articles : Articles) {
textView.text = articles.articleName
}
companion object {
fun create(parent: ViewGroup): ArticlesViewHolder {
return ArticlesViewHolder(LayoutInflater.from(parent.context).inflate(R.layout.article_item_layout, parent, false))
}
}
}
this is how i set data from my activity
val db = AppDatabase.getDatabase(applicationContext)
dao = db.articleDao()
val recyclerView = findViewById<RecyclerView>(R.id.categories_recycle_view)
recyclerView.layoutManager = LinearLayoutManager(this)
recyclerView.adapter = CategoriesAdapter()
adapter.setItems(dao.getAllArticlesAndCategories())
Can anyone help.
P.s i'm new to kotlin
Instead of
adapter.setItems(dao.getAllArticlesAndCategories())
Use live data observer to avoid processing on main thread and debug in observe function of live data to confirm you are receiving correct data from DB.
calling code one line of code is missing
val db = AppDatabase.getDatabase(applicationContext)
dao = db.articleDao()
val recyclerView = findViewById<RecyclerView>(R.id.categories_recycle_view)
recyclerView.layoutManager = LinearLayoutManager(this)
recyclerView.adapter = CategoriesAdapter()
adapter.setItems(dao.getAllArticlesAndCategories())
it should be:
val db = AppDatabase.getDatabase(applicationContext)
dao = db.articleDao()
val recyclerView = findViewById<RecyclerView>(R.id.categories_recycle_view)
recyclerView.layoutManager = LinearLayoutManager(this)
adapter=CategoriesAdapter()
adapter.setItems(dao.getAllArticlesAndCategories())
recyclerView.adapter = adapter
I would like to thank for the question and the code
I'm successfully passing data from MainActivity to my recyclerView via adapter, and my view with items is rendering correctly. However, I need to change one member of my item object on click (status), and i wrote a method for that (updateStatus), and it works great, it changes the value and save it to database.
But i cannot refresh my recyclerView, so it could render changed Status attribute. I need to go back on my phone, reenter, and then it renders it correctly. I have tried everything, from notifyDataSetChanged to restarting adapter, no luck. There is something missing and I can't find what.
Here is my MainActivity class
class MainActivity : AppCompatActivity() {
private var posiljkaDAO: PosiljkaDAO? = null
private var dostavnaKnjizicaDAO: DostavnaKnjizicaDAO? = null
private var allItems: ArrayList<DostavnaKnjizicaModel> = arrayListOf()
var adapter = RecycleViewAdapter(allItems)
private var eSifraPosiljke: EditText? = null
#RequiresApi(Build.VERSION_CODES.O)
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_listview)
//get logo
supportActionBar!!.setDisplayShowHomeEnabled(true)
supportActionBar!!.setLogo(R.drawable.logo_bp)
supportActionBar!!.setDisplayUseLogoEnabled(true)
dostavnaKnjizicaDAO = DostavnaKnjizicaDAO(this)
dostavnaKnjizicaDAO?.closeDB()
getAllItems(this)
//connecting adapter and recyclerView
adapter = RecycleViewAdapter(allItems)
recycleView.adapter = adapter
recycleView.layoutManager = LinearLayoutManager(this)
recycleView.setHasFixedSize(true)
eSifraPosiljke = findViewById<EditText>(R.id.eSifraPosiljke)
posiljkaDAO = PosiljkaDAO(this)
}
//method that gets all items from database
private fun getAllItems(context: Context) {
var dostavenFromLOcal = dostavnaKnjizicaDAO?.getAllLocalDostavneKnjizice(context)
if (dostavenFromLOcal != null) {
allItems = dostavenFromLOcal
}
}
//method that changes status of an item
fun changeStatus(context: Context, IdDostavne: Int, statusDostavne: Int) {
dostavnaKnjizicaDAO = DostavnaKnjizicaDAO(context)
dostavnaKnjizicaDAO?.changeStatus(IdDostavne, statusDostavne)
getAllItems(context)
adapter.notifyDataSetChanged()
}
}
and my Adapter class
class RecycleViewAdapter(var dostavneKnjiziceBP: ArrayList<DostavnaKnjizicaModel>)
: RecyclerView.Adapter<RecycleViewAdapter.ViewHolder>() {
class ViewHolder(view: View) : RecyclerView.ViewHolder(view){
val nazivPrimaoca: TextView = view.txtNazivPrimaoca
val brojPosiljke: TextView = view.txtBrojPosiljke
val statusDostave: TextView = view.txtStatusDostave
val imgMore: ImageView = view.img_more
val context: Context = view.context
}
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): ViewHolder {
val layoutView = LayoutInflater.from(parent.context).inflate(R.layout.urucenje_posiljke_layout, parent, false)
return ViewHolder(layoutView)
}
override fun getItemCount() = dostavneKnjiziceBP.size
#RequiresApi(Build.VERSION_CODES.KITKAT)
override fun onBindViewHolder(holder: ViewHolder, position: Int) {
//New variable to get all modeliPosiljakaBP and their position
var dosKnjizica = dostavneKnjiziceBP[position]
val mainActivity = MainActivity()
//Sending data to layout for display in specific field
if (dosKnjizica.naziv_primaoca != null) {
holder.brojPosiljke.text = "${dosKnjizica.id_dostavna_knjizica}, "
holder.nazivPrimaoca.text = "${dosKnjizica.naziv_primaoca}"
if (dosKnjizica.naziv_primaoca!!.length > 25) {
holder.nazivPrimaoca.text = "${dosKnjizica.naziv_primaoca!!.subSequence(0, 25)}..."
}
} else {
holder.brojPosiljke.text = "${dosKnjizica.id_dostavna_knjizica}"
holder.nazivPrimaoca.text = ""
}
holder.statusDostave.text = "${dosKnjizica.status_dostave_naziv}"
when (dosKnjizica.status_dostave) {
StatusDostaveEnum.Neurucena.value -> {
holder.statusDostave.setTextColor(Color.RED)
}
StatusDostaveEnum.Uruceno.value, StatusDostaveEnum.ZaRejon.value, StatusDostaveEnum.Nadoslano.value, StatusDostaveEnum.Izgubljeno.value -> {
holder.statusDostave.setTextColor(Color.GREEN)
}
StatusDostaveEnum.Obavjesteno.value, StatusDostaveEnum.ZaNarednuDostavu.value -> {
holder.statusDostave.setTextColor(Color.BLUE)
}
StatusDostaveEnum.Retour.value -> {
holder.statusDostave.setTextColor(Color.parseColor("#dda0dd"))
}
}
//Calling menu menu_pregled_drugih_vrsta_posiljke to display menu options on click on three dots
holder.imgMore.setOnClickListener {
val popupMenu = PopupMenu(holder.context, it, Gravity.START)
popupMenu.setOnMenuItemClickListener { item ->
when (item.itemId) {
R.id.uruci -> {
//calling new activity from second item in dropdown menu
holder.imgMore.context.startActivity(
Intent(holder.imgMore.context, MainActivityInfo::class.java).putExtra(
"Id", dosKnjizica.id_dostavna_knjizica.toString()
)
)
true
}
//here i am calling my changeStatus method from MainActivity
R.id.obavjesti -> {
mainActivity.changeStatus(holder.context, dosKnjizica.id_dostavna_knjizica!!, StatusDostaveEnum.Uruceno.value)
Toast.makeText(holder.context, "obavjesti", Toast.LENGTH_SHORT).show()
true
}
R.id.vrati -> {
Toast.makeText(holder.context, "vrati", Toast.LENGTH_SHORT).show()
true
}
else -> false
}
}
popupMenu.inflate(R.menu.menu_urucenje_posiljke)
popupMenu.show()
}
}
}
Your adapter doesn't have the updated data. Initially, you fetch all data from the database and create an adapter with it: adapter = RecycleViewAdapter(allItems). Afterwards, you are updating the database, calling getAllItems(Context) but you don't pass the data to the adapter.
Add the line adapter.dostavneKnjiziceBP = allItems to the changeStatus method like this:
//method that changes status of an item
fun changeStatus(context: Context, IdDostavne: Int, statusDostavne: Int) {
dostavnaKnjizicaDAO = DostavnaKnjizicaDAO(context)
dostavnaKnjizicaDAO?.changeStatus(IdDostavne, statusDostavne)
getAllItems(context)
adapter.dostavneKnjiziceBP = allItems
adapter.notifyDataSetChanged()
}
Save dostavneKnjiziceBP as a private var inside the adapter and create functions for assigning and updating that ArrayList from within the adapter, using notifyDataSetChanged() everytime a change is done.
class RecycleViewAdapter internal constructor(
context: Context
) : RecyclerView.Adapter<RecycleViewAdapter.ViewHolder>() {
private var items = ArrayList<DostavnaKnjizicaModel>()
// ...
internal fun setItems(items: ArrayList<DostavnaKnjizicaModel>) {
this.items = items
notifyDataSetChanged()
}
override fun getItemCount() = this.items.size
}
Also, try using adapter.notifyItemChanged(updateIndex); if you know the index of the updated item.
I have recyclerview with checkbox and I want to checklist all the data using button. I have trying this tutorial, but when i click the button, the log is call the isSelectedAll function but can't make the checkbox checked. what wrong with my code?
this is my adapter code
var isSelectedAll = false
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): ListApproveDeatilViewHolder {
val itemView = LayoutInflater.from(parent.context)
.inflate(R.layout.activity_list_approve_row, parent, false)
return ListApproveDeatilViewHolder(itemView)
}
private lateinit var mSelectedItemsIds: SparseBooleanArray
fun selectAll() {
Log.e("onClickSelectAll", "yes")
isSelectedAll = true
notifyDataSetChanged()
}
override fun onBindViewHolder(holder: ListApproveDeatilViewHolder, position: Int) {
val approve = dataSet!![position]
holder.soal.text = approve.title
holder.kategori.text = approve.kategori
if (!isSelectedAll){
holder.checkBox.setChecked(false)
} else {
holder.checkBox.setChecked(true)
}
}
and this is my activity code
override fun onCreate(savedInstanceState: Bundle?) {
private var adapter: ListApproveDetailAdapter? = null
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_list_approve)
ButterKnife.bind(this)
getData()
// this is my button onclick code
select.setOnClickListener(){
if (select.getText().toString().equals("Select all")){
Toast.makeText(this, "" + select.getText().toString(), Toast.LENGTH_SHORT).show()
adapter?.selectAll()
select.setText("Deselect all")
} else {
Toast.makeText(this, "" + select.getText().toString(), Toast.LENGTH_SHORT).show()
select.setText("Select all")
}
}
}
//this is for get my data for the recyclerview
fun getData() {
val created_by = intent.getStringExtra(ID_SA)
val tgl_supervisi = intent.getStringExtra(TGL_SURVEY)
val no_dlr = intent.getStringExtra(NO_DLR)
API.getListApproveDetail(created_by, tgl_supervisi, no_dlr).enqueue(object : Callback<ArrayList<ListApprove>> {
override fun onResponse(call: Call<ArrayList<ListApprove>>, response: Response<ArrayList<ListApprove>>) {
if (response.code() == 200) {
tempDatas = response.body()
Log.i("Data Index History", "" + tempDatas)
recyclerviewApprove?.setHasFixedSize(true)
recyclerviewApprove?.layoutManager = LinearLayoutManager(this#ListApproveActivity)
recyclerviewApprove?.adapter = ListApproveDetailAdapter(tempDatas)
adapter?.notifyDataSetChanged()
} else {
Toast.makeText(this#ListApproveActivity, "Error", Toast.LENGTH_LONG).show()
}
swipeRefreshLayout.isRefreshing = false
}
override fun onFailure(call: Call<ArrayList<ListApprove>>, t: Throwable) {
Toast.makeText(this#ListApproveActivity, "Error", Toast.LENGTH_SHORT).show()
swipeRefreshLayout.isRefreshing = false
}
})
}
thankyou for any help :)
I am posting the answer with implementation of demo project. I haven't modified your code but as per your requirement i have done this.
MainActivity class:
class MainActivity : AppCompatActivity() {
var selectAll: Boolean = false;
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
val recyclerView = findViewById<RecyclerView>(R.id.recyclerView) as RecyclerView
val btnSelectAll = findViewById<Button>(R.id.btnSelectAll) as Button
//adding a layoutmanager
recyclerView.layoutManager = LinearLayoutManager(this, LinearLayout.VERTICAL, false)
//crating an arraylist to store users using the data class user
val users = ArrayList<User>()
//adding some dummy data to the list
users.add(User("Piyush", "Ranchi"))
users.add(User("Mehul", "Chennai"))
users.add(User("Karan", "TamilNadu"))
users.add(User("Bela", "Kolkata"))
//creating our adapter
val adapter = CustomAdapter(users, selectAll)
//now adding the adapter to recyclerview
recyclerView.adapter = adapter
btnSelectAll.setOnClickListener {
if (!selectAll) {
selectAll = true
} else {
selectAll = false
}
adapter?.selectAllCheckBoxes(selectAll)
}
}
}
User class:
data class User(val name: String, val address: String)
Adapter class:
class CustomAdapter(val userList: ArrayList<User>, val selectAll: Boolean) :
RecyclerView.Adapter<CustomAdapter.ViewHolder>() {
var selectAllA = selectAll;
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): CustomAdapter.ViewHolder {
val v = LayoutInflater.from(parent.context).inflate(R.layout.list_layout, parent, false)
return ViewHolder(v)
}
override fun onBindViewHolder(holder: CustomAdapter.ViewHolder, position: Int) {
holder.textViewName.text = userList[position].name;
if (!selectAllA){
holder.checkBox.setChecked(false)
} else {
holder.checkBox.setChecked(true)
}
}
//this method is giving the size of the list
override fun getItemCount(): Int {
return userList.size
}
//the class is hodling the list view
class ViewHolder(itemView: View) : RecyclerView.ViewHolder(itemView) {
val textViewName = itemView.findViewById(R.id.textViewUsername) as TextView
val checkBox = itemView.findViewById(R.id.checkbox) as CheckBox
}
fun selectAllCheckBoxes(selectAll: Boolean) {
selectAllA = selectAll
notifyDataSetChanged()
}
}
As i already mentioned in comments you are using two different adapter instance .
Now i see you have declared adapter globally .
Just modify your code as follows and make sure response.body() have data int it :
if (response.code() == 200) {
tempDatas = response.body()
Log.i("Data Index History", "" + tempDatas)
recyclerviewApprove?.setHasFixedSize(true)
recyclerviewApprove?.layoutManager = LinearLayoutManager(this#ListApproveActivity)
adapter = ListApproveDetailAdapter(tempDatas)
recyclerviewApprove?.adapter=adapter
} else {
Toast.makeText(this#ListApproveActivity, "Error", Toast.LENGTH_LONG).show()
}
Add one variable in model class.
like var isSelect : Boolean
In your selectAll() method update adpter list and notify adapter.
Edit:
in the adapter class.
if (approve.isSelect){
holder.checkBox.setChecked(true)
} else {
holder.checkBox.setChecked(false)
}
Hope this may help you.
OR
If you are using AndroidX then use should use one recyclerview features.
androidx.recyclerview.selection
A RecyclerView addon library providing support for item selection. The
library provides support for both touch and mouse driven selection.
Developers retain control over the visual representation, and the
policies controlling selection behavior (like which items are eligible
for selection, and how many items can be selected.)
Reference from here