problem populate spinner android kotlin with room database - android

I want to populate spinner with room database in kotlin but items in spinner are different. the number of items are true. exactly I want to make ArrayList of title in Category Class and show them in spinner in a fragment
#Entity(tableName = "cat_table")
class Category(val title: String,
val fulType: Int,
val SaleP: Long,
val BuyP: Long,
var created: Date = Date()
) {
#PrimaryKey(autoGenerate = true)
var id: Int = 0
}`
by this an want to show all title in ArrayList and set to spinner
private fun initData() {
val packageTypesAdapter = context?.let {ArrayAdapter<Any>(it,android.R.layout.simple_spinner_item)}
catViewModel!!.allCats.observe(viewLifecycleOwner, Observer { packageTypes ->
packageTypes?.forEach {packageTypesAdapter!!.add(it)}
})
spinner2.adapter = packageTypesAdapter
spinner2.onItemSelectedListener = object : AdapterView.OnItemSelectedListener {
override fun onItemSelected(adapterView: AdapterView<*>, view: View, i: Int, l: Long) {
Toast.makeText(context, "$packageTypesAdapter", Toast.LENGTH_SHORT).show()
//if (i == 0) {
// loadAllTodos()
//} else {
// val string: String = parent.getItemAtPosition(position).toString()
// loadFilteredTodos(string)
//}
}
override fun onNothingSelected(adapterView: AdapterView<*>) {
}
}
}`
if use this query
#get:Query("SELECT * FROM cat_table WHERE title ")
val allCatTitle: LiveData<List<Category>>
spinner nothing to show and below query are like this picture
#get:Query("SELECT * FROM cat_table ORDER BY created DESC")
val allCatByDate: LiveData<List<Category>>
Please check the photo

In case someone else bumps into the same issue. Here's how I did it a while ago (Kotlin).
Dao
#Query("SELECT deviceName FROM device_table WHERE deviceType = :deviceType")
fun getDevice(deviceType: String): LiveData<List<String>>
Repository
fun getDevice(deviceType: String): LiveData<List<String>> {
return deviceDao.getDevice(deviceType)
}
ViewModel
fun getDevice(deviceType: String): LiveData<List<String>> {
return repository.getDevice(deviceType)
}
And finally in my fragment:
private fun initSpinnerData() {
val spinner3 = view?.findViewById<Spinner>(R.id.spinnerRecord_devices)
if (spinner3 != null) {
val allDevices = context?.let {
ArrayAdapter<Any>(it, R.layout.spinner_text)
}
mDevicesViewModel.getDevice("Appliance")
.observe(viewLifecycleOwner, { devices ->
devices?.forEach {
allDevices?.add(it)
}
})
spinner3.adapter = allDevices
spinner3.onItemSelectedListener = object : AdapterView.OnItemSelectedListener {
override fun onItemSelected(
parent: AdapterView<*>?,
view: View?,
position: Int,
id: Long
) {
Toast.makeText(requireContext(), "$allDevices", Toast.LENGTH_LONG).show()
}
override fun onNothingSelected(parent: AdapterView<*>?) {
TODO("Not yet implemented")
}
}
}
}

Related

RecyclerView is not updated when an update occurs in Room

I have a RecyclerView where an item can be edited via a DialogFragment, so when an item is clicked a Dialog is shown, then I can change some properties of that item, the issue is that RecyclerView is not updated with the updated properties and I have to force a notifyItemChanged when the Dialog is closed.
When an item in RecyclerView is clicked I set a MutableLiveData in my ViewModel so then it can be manipulated in the Dialog.
My ViewModel looks like this:
#HiltViewModel
class DocumentProductsViewModel #Inject constructor(private val repository: DocumentProductsRepository) :
ViewModel() {
val barcode = MutableLiveData<String>()
private val _selectedProduct = MutableLiveData<DocumentProduct>()
val selectedProduct: LiveData<DocumentProduct> = _selectedProduct
private val _selectedDocumentId = MutableLiveData<Long>()
val selectedDocumentId: LiveData<Long> = _selectedDocumentId
val products: LiveData<List<DocumentProduct>> = _selectedDocumentId.switchMap { documentId ->
repository.getDocumentProducts(documentId).asLiveData()
}
fun insert(documentProduct: DocumentProduct) = viewModelScope.launch {
repository.insert(documentProduct)
}
fun setProductQuantity(quantity: Float) {
_selectedProduct.value = _selectedProduct.value.also {
it?.timestamp = System.currentTimeMillis()
it?.quantity = quantity
}
update()
}
fun start(documentId: Long?) = viewModelScope.launch{
if (documentId == null) {
_selectedDocumentId.value = repository.getHeaderByType("Etichette")?.id
}
documentId?.let { documentId ->
_selectedDocumentId.value = documentId
}
}
fun select(product: DocumentProduct) {
_selectedProduct.value = product
}
fun delete() = viewModelScope.launch {
_selectedProduct.value?.let { repository.delete(it) }
}
private fun update() = viewModelScope.launch {
_selectedProduct.value?.let { repository.update(it) }
}
}
And in my fragment I'm subscribed to products as this:
private fun initRecyclerView() {
binding.rvProducts.adapter = adapter
viewModel.products.observe(viewLifecycleOwner) { products ->
val productsCount = products.count()
binding.tvProductsCount.text =
resources.getQuantityString(R.plurals.articoli, productsCount, productsCount)
// TODO: create amount string and set it with resources
binding.tvProductsAmount.text = productsCount.toEuro()
adapter.submitList(products)
binding.rvProducts.smoothScrollToPosition(adapter.itemCount - 1)
}
initSwipe(adapter)
}
When setProductQuantity is called the RecyclerView remains unchanged until notify is called while delete works fine without the necessity of calling any notify on RecyclerView.
UPDATE:
The item position is actually changed in RecyclerView as it's sorted by it's last changed timestamp BUT not the quantity field.
Here is my Adapter:
class DocumentProductsListAdapter : ListAdapter<DocumentProduct, DocumentProductsListAdapter.ViewHolder>(ProductDiffCallback) {
override fun onCreateViewHolder(viewGroup: ViewGroup, viewType: Int): ViewHolder {
val view: View = LayoutInflater.from(viewGroup.context)
.inflate(R.layout.layout_item, viewGroup, false)
return ViewHolder(view)
}
override fun onBindViewHolder(holder: ViewHolder, position: Int) {
val product = getItem(position)
holder.bind(product)
}
class ViewHolder(view: View) : RecyclerView.ViewHolder(view) {
val barcode: TextView = itemView.findViewById(R.id.barcode)
val quantity: TextView = itemView.findViewById(R.id.quantity)
val description: TextView = itemView.findViewById(R.id.description)
val unitOfMeasure: TextView = itemView.findViewById(R.id.unitOfMeasure)
fun bind(product: DocumentProduct) {
barcode.text = product.barcode
quantity.text = product.quantity.formatForQta().replace(".", ",")
if (product.labelType != null && product.labelType != "") {
unitOfMeasure.text = product.labelType
} else {
unitOfMeasure.text = product.unitOfMeasure?.lowercase(Locale.ITALIAN)
}
description.text = product.description ?: "-"
}
}
}
object ProductDiffCallback : DiffUtil.ItemCallback<DocumentProduct>() {
override fun areItemsTheSame(oldItem: DocumentProduct, newItem: DocumentProduct): Boolean {
return oldItem.id == newItem.id
}
override fun areContentsTheSame(oldItem: DocumentProduct, newItem: DocumentProduct): Boolean {
return oldItem == newItem
}
}
data class DocumentProduct(
#PrimaryKey(autoGenerate = true)
var id: Long,
var barcode: String,
#Json(name = "desc")
var description: String?,
#ColumnInfo(defaultValue = "PZ")
#Json(name = "um")
var unitOfMeasure: String?,
#Json(name = "qta")
var quantity: Float,
#Json(name = "id_testata")
var documentId: Long,
#Json(name = "tipo_frontalino")
var labelType: String?,
var timestamp: Long?
) {
constructor(barcode: String, documentId: Long, labelType: String?) : this(
0,
barcode,
null,
"PZ",
1f,
documentId,
labelType,
null
)
override fun equals(other: Any?): Boolean {
return super.equals(other)
}
override fun hashCode(): Int {
return super.hashCode()
}
}
You have the implementations of areContentsTheSame() and areItemsTheSame() swapped.
areContentsTheSame() is asking if everything in the two items being compared is the same. Therefore, if the class has a proper equals()/hashcode() for all properties used by the ViewHolder, you can use oldItem == newItem. If you use a data class with all relevant properties in the primary constructor, then you don't need to manually override equals()/hashcode().
areItemsTheSame() is asking if the two items represent the same conceptual row item, with possible differences in their details. So it should be oldItem.id == newItem.id.
The problem with your data class is that you are overriding equals()/hashcode() without providing any implementation at all. This is effectively disabling the proper implementations that are provided by the data modifier by calling through to the super implementation in the Any class. You should not override them at all when you use data class.

Getting always default values of items from RecyclerViewAdapter

I have an activity that has a recyclerview. Each item of the recyclerview has 3 components: spinner, EditText and an ImageButton
In the activity, there's an "add users" button that should save all the info in the recycleViewer to DB. To give more context, there's also an "add user" button that adds another item to the recycleViewer.
The problem is that when I call the saveUsers function from the activity, who calls the newUserAdapter.getUsers(), that function always returns the list of items of the RecycleView empty (the editText and the Spinner) even if the user has modified the info on the recycleView
Here is my activity
class AddUser : AppCompatActivity() {
private lateinit var binding: ActivityAddUserBinding
private lateinit var newUserAdapter : AddUserRecyclerViewAdapter
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
binding = ActivityAddUserBinding.inflate(layoutInflater)
newUserAdapter = AddUserRecyclerViewAdapter()
val b = User("","")
newUserAdapter.addItem(b)
binding.recyclerViewUser.adapter = newUserAdapter
setContentView(binding.root)
}
fun addNewUserRow(view: View) {
Timber.i("AddUser addNewUserRow called")
val b = User("","")
newUserAdapter.addItem(b)
}
fun saveUsers(view: View) {
if(newUserAdapter.itemCount > 0)
{
var usr = newUserAdapter.getUsers()
//TODO: save usr to DataBase
}
else
{
Snackbar.make(view, R.string.delete_user, Snackbar.LENGTH_LONG).show()
}
}
}
This is my User data class:
data class User (
var name: String = String(),
var department: String = String()
)
And my RecycleViewAdapter:
class AddUserRecyclerViewAdapter : RecyclerView.Adapter<AddUserRecyclerViewAdapter.AddUserViewHolder>() {
private var allUsers = ArrayList<User>()
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): AddUserViewHolder {
Timber.i("User onCreateViewHolder")
val view = AddUserItemBinding.inflate(
LayoutInflater.from(parent.context),
parent,
false
)
val tempUser = AddUserViewHolder(view)
tempUser.deleteBtn.setOnClickListener {
Timber.i("NewUser setOnClickListener " + tempUser.bindingAdapterPosition)
if (this.itemCount > 1)
{
deleteItem(tempUser.bindingAdapterPosition)
}
else
{
//At least one item, we don't let delete the last one
Snackbar.make(it, R.string.delete_user, Snackbar.LENGTH_LONG).show()
}
}
return tempUser
}
override fun onBindViewHolder(holderUser: AddUserViewHolder, position: Int) {
Timber.i("NewUser onBindViewHolder $position")
val item = allUsers[position]
holderUser.nameEt.setText(item.name.toString())
}
private fun deleteItem(pos: Int) {
Timber.i("NewUser deleteItem $pos")
allUsers.removeAt(pos)
// call notifyDataSetChanged() to notify our adapter.
notifyItemRemoved(pos)
}
fun addItem(item: User) {
allUsers.add(item)
// call notifyDataSetChanged() to notify our adapter.
notifyItemInserted(allUsers.size -1)
}
fun getUsers(): ArrayList<User> {
return allUsers
}
override fun getItemCount(): Int {
Timber.i("NewUser getItemCount called" + allUsers.size)
return allUsers.size
}
inner class AddUserViewHolder(binding: AddUserItemBinding) :
RecyclerView.ViewHolder(binding.root) {
var nameEt: EditText = binding.etName
var deleteBtn : ImageButton = binding.btnDelete
var spinnerDepartment : Spinner = binding.spinnerDepartment
}
}
Edit
As it seems that someone downvoted for lack of information, let me say it in different words. This is the function in RecycleViewAdapter:
fun getUsers(): ArrayList<User> {
return allUsers
}
Who is called when a button is clicked from the activity:
fun saveUsers(view: View) {
if(newUserAdapter.itemCount > 0)
{
var usr = newUserAdapter.getUsers()
//TODO: save usr to DataBase
}
else
{
Snackbar.make(view, R.string.delete_user, Snackbar.LENGTH_LONG).show()
}
}
So the var usr is where I get a list of empty users, where I expected to get a list of users with the information filled in the RecycleView.
You should update the property of the user in the ArrayList when you are changing the text with an addTextChangedListener
override fun onBindViewHolder(holderUser: AddUserViewHolder, position: Int) {
Timber.i("NewUser onBindViewHolder $position")
val item = allUsers[position]
holderUser.nameEt.setText(item.name.toString())
holderUser.nameEt.addTextChangedListener(object : TextWatcher {
override fun afterTextChanged(p0: Editable?) { }
override fun beforeTextChanged(p0: CharSequence?, p1: Int, p2: Int, p3: Int) { }
override fun onTextChanged(text: CharSequence?, p1: Int, p2: Int, p3: Int) {
// Update user instance in allUsers
allUsers[position].name = text.toString()
}
})
}
You may want also want to define an onItemSelectedListener on the Spinner to update the selected department as well.

Android spinner item cannot be selected when not creating from resource

I am using kotlin and android 8.0, I have 2 spinners in my code, 1 of them was created using a string array from resource and another was created with an ArrayList. For the spinner that was created with an ArrayList, when clicking on the item, it does not run the OnItemSelected function and does not update the spinner.
Here is my kotlin code for the spinner
class MainActivity : AppCompatActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
val modules = ArrayList<Module>()
val bufferedReader = BufferedReader(InputStreamReader(resources.openRawResource(R.raw.mod_code)))
var line = bufferedReader.readLine()
while(line != null) {
val values = line.split(",")
modules.add(Module(values[0].replace("\uFEFF", "").toInt(), values[1], values[2].replace("\uFEFF", "").toDouble()))
line = bufferedReader.readLine()
}
val moduleCodeArray = ArrayList<String>()
val yearSpinner: Spinner = findViewById(R.id.year)
yearSpinner.onItemSelectedListener = object : AdapterView.OnItemSelectedListener{
override fun onItemSelected(parent: AdapterView<*>?, view: View?, position: Int, id: Long) {
val item = parent?.getItemAtPosition(position).toString()
Toast.makeText(parent?.context, "Selected: $item", Toast.LENGTH_LONG).show()
moduleCodeArray.clear()
for(module in modules) {
if(module.year == position + 1) {
moduleCodeArray.add(module.moduleCode)
}
}
}
override fun onNothingSelected(parent: AdapterView<*>?) {
}
}
ArrayAdapter.createFromResource(
this,
R.array.years,
R.layout.custom_spinner
).also { adapter ->
adapter.setDropDownViewResource(R.layout.custom_spinner_dropdown)
yearSpinner.adapter = adapter
}
println(moduleCodeArray)
val moduleCodeSpinner = findViewById<Spinner>(R.id.module_code)
moduleCodeSpinner.onItemSelectedListener = object : AdapterView.OnItemSelectedListener {
override fun onItemSelected(parent: AdapterView<*>?, view: View?, position: Int, id: Long) {
val item = parent?.getItemAtPosition(position).toString()
Toast.makeText(parent?.context, "Selected: $item", Toast.LENGTH_LONG).show()
}
override fun onNothingSelected(parent: AdapterView<*>?) {}
}
ArrayAdapter(
this,
R.layout.custom_spinner,
moduleCodeArray
).also { adapter ->
adapter.setDropDownViewResource(R.layout.custom_spinner_dropdown)
moduleCodeSpinner.adapter = adapter
}
}
}
EDIT: I have fixed the problem! In the code I provided, you can see my ArrayList being filled in an onItemSelected function, for some reason, the ArrayAdapter has to be in that function as well, so the correct code should look something like this.
val modules = ArrayList<Module>()
val bufferedReader = BufferedReader(InputStreamReader(resources.openRawResource(R.raw.mod_code)))
var line = bufferedReader.readLine()
while(line != null) {
val values = line.split(",")
modules.add(Module(values[0].replace("\uFEFF", "").toInt(), values[1], values[2].replace("\uFEFF", "").toDouble()))
line = bufferedReader.readLine()
}
val moduleCodeArray = ArrayList<String>()
val moduleCodeSpinner = findViewById<Spinner>(R.id.module_code)
val yearSpinner: Spinner = findViewById(R.id.year)
yearSpinner.onItemSelectedListener = object : AdapterView.OnItemSelectedListener{
override fun onItemSelected(parent: AdapterView<*>?, view: View?, position: Int, id: Long) {
val item = parent?.getItemAtPosition(position).toString()
Toast.makeText(parent?.context, "Selected: $item", Toast.LENGTH_LONG).show()
moduleCodeArray.clear()
for(module in modules) {
if(module.year == position + 1) {
moduleCodeArray.add(module.moduleCode)
}
}
ArrayAdapter(
applicationContext,
R.layout.custom_spinner,
moduleCodeArray
).also { adapter ->
adapter.setDropDownViewResource(R.layout.custom_spinner_dropdown)
moduleCodeSpinner.adapter = adapter
}
}
override fun onNothingSelected(parent: AdapterView<*>?) {
}
}
ArrayAdapter.createFromResource(
this,
R.array.years,
R.layout.custom_spinner
).also { adapter ->
adapter.setDropDownViewResource(R.layout.custom_spinner_dropdown)
yearSpinner.adapter = adapter
}
moduleCodeSpinner.onItemSelectedListener = object : AdapterView.OnItemSelectedListener {
override fun onItemSelected(parent: AdapterView<*>?, view: View?, position: Int, id: Long) {
val item = parent?.getItemAtPosition(position).toString()
Toast.makeText(parent?.context, "Selected: $item", Toast.LENGTH_LONG).show()
}
override fun onNothingSelected(parent: AdapterView<*>?) {}
}
Your Code Seems correct , I have used the same code provided by you and it worked correctly.
May you have error in custom_spinner or custom_spinner_dropdown !![You can share these layouts ]
This is what I have done:
spinner example

Using roomdatabase query for search between products

before get to my issue let me tell you how my app works.
I have A little Grocery App and fetch data from an api with retrofit and after that save it to Roomdatabase.
For better Ui experiment I need to implement searchview with an edittext on my main screen .
So , I decide to code a query in my dao and get all data by title filter .
But the problem is that , when I fill the edittext and click on button to get the product that I filter it nothing happened and doesn't any search .
Well , I guess maybe my problem would be with my code that I implement in repository and viewmodel to insert data to roomdatabase . if not , what's wrong with my code ?
I will be appreciated if you look at my code .
and here is my code :
This is room table :
#Entity(tableName = "newTable")
data class RoomEntity(
#PrimaryKey
(autoGenerate = true)
val id : Int? ,
#ColumnInfo val title: String,
#ColumnInfo val image: String
)
Dao :
#Dao
interface RoomDaoQuery {
#Query("SELECT * FROM newTable")
fun getAllProduct () : LiveData<List<RoomEntity>>
#Insert(onConflict = OnConflictStrategy.REPLACE)
fun insertDataToDatabase(model : List<RoomEntity>)
#Query("SELECT * FROM newTable WHERE title LIKE '%' || :search || '%'")
fun searchByName(search: String): List<RoomEntity>
}
Repository :
class Repository(private val database: DatabaseRoom) {
fun getAllProduct() = database.GetDao.getAllProduct()
private fun retrofit(): ApiRetrofit {
return Retrofit.Builder()
.baseUrl("http://192.168.43.106/")
.addConverterFactory(GsonConverterFactory.create(GsonBuilder().create()))
.build()
.create(ApiRetrofit::class.java)
}
suspend fun fettchAllDat(): List<RoomEntity> {
return retrofit().getProduct()
}
suspend fun insertToDatabase(model : List<RoomEntity>) {
database.GetDao.insertDataToDatabase(fettchAllDat())
}
// this is for local search
fun searchWithName (title : String) : List<RoomEntity> {
return database.GetDao.searchByName(title)
}
}
Viewmodel:
class ViewmodelRoom(application: Application) : AndroidViewModel(application) {
val product = MutableLiveData<List<RoomEntity>>()
private val repository = Repository(DatabaseRoom.getInstance(application))
private var viewModelJob = SupervisorJob()
private val viewModelScope = CoroutineScope(viewModelJob + Dispatchers.Default)
fun getAllProduct() = repository.getAllProduct()
fun setup() {
viewModelScope.launch{
product.postValue(repository.fettchAllDat())
insertall()
}
}
fun insertall() {
viewModelScope.launch {
repository.insertToDatabase(repository.fettchAllDat())
}
}
fun searchByTitle(title : String) = CoroutineScope(Dispatchers.Default).launch{
repository.searchWithName(title)
}
}
and MainActivity :
class MainActivity : AppCompatActivity() {
val viewModel: ViewmodelRoom by lazy {
ViewModelProvider(this).get(ViewmodelRoom::class.java)
}
#RequiresApi(Build.VERSION_CODES.M)
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
val editText: EditText = findViewById(R.id.edittext)
val search: ImageView = findViewById(R.id.searchview)
val recyclerView = findViewById<RecyclerView>(R.id.recyclerview)
search.setOnClickListener {
viewModel.searchByTitle(editText.text.toString())
editText.text.clear()
}
editText.addTextChangedListener(object : TextWatcher {
override fun onTextChanged(p0: CharSequence?, p1: Int, p2: Int, p3: Int) {
viewModel.searchByTitle(editText.text.toString())
}
override fun afterTextChanged(p0: Editable?) {
}
override fun beforeTextChanged(p0: CharSequence?, p1: Int, p2: Int, p3: Int) {
}
})
if (isNetworkAvaliable(applicationContext)) {
viewModel.setup()
viewModel.product.observe(this, Observer {
recyclerView.apply {
layoutManager = GridLayoutManager(this#MainActivity, 2)
adapter = RecyclerAdapterMain(it, this#MainActivity)
}
})
} else {
viewModel.getAllProduct().observe(this, Observer { list ->
recyclerView.apply {
layoutManager = GridLayoutManager(this#MainActivity, 2)
adapter = RecyclerAdapterMain(list, this#MainActivity)
}
})
}
}
finally I get to a proper result .
I put my code here , I hope maybe useful for someone .
the Dao :
#Query("SELECT * FROM newTable WHERE title LIKE :name")
fun search (name : String) :LiveData<List<RoomEntity>>
Repository :
fun search(name : String): LiveData<List<RoomEntity>>{
return database.GetDao.search(name)
}
fun search(name : String) : LiveData<List<RoomEntity>> {
return repository.search(name)
}
MainActivity :
val editText: EditText = findViewById(R.id.edittext)
val search: ImageView = findViewById(R.id.searchview)
recyclerView = findViewById(R.id.recyclerview)
search.setOnClickListener {
// this is an extention function that observe data
searchProduct(editText.text.toString())
}
editText.addTextChangedListener(object : TextWatcher {
override fun onTextChanged(p0: CharSequence?, p1: Int, p2: Int, p3: Int) {
searchProduct(editText.text.toString())
}
override fun afterTextChanged(p0: Editable?) {
}
override fun beforeTextChanged(p0: CharSequence?, p1: Int, p2: Int, p3: Int) {
}
})
private fun searchProduct(title : String) {
var searchText = title
searchText = "%$title%"
viewModel.search(searchText).observe(this#MainActivity , Observer {
d("main" , "$it")
recyclerView.apply {
layoutManager = GridLayoutManager(this#MainActivity, 2)
adapter = RecyclerAdapterMain(it, this#MainActivity)
}
})
}

Android Kotlin RecyclerView Search Item with EditText with data from Data Class

So I have a RecyclerView which data is populated with data from some Data Class. I want to Apply a search item function for this recyclerview. Back when I don't use Data Classes, I followed this tutorial (The tutorial is in Java).
Now that I'm using a data class since I fetch the data that populate the recyclerview from an API endpoint, I'm quite confused on how to apply the search function in the current recyclerview.
(I fetch the data using library Retrofit if you wondering.)
This is the code snippet from the fragment:
RefundListFragment.kt
private fun fetchRefundListData() {
NetworkConfig().getRefundListDetailService().getRefundList().enqueue(object :
Callback<RefundListPOJODataClass> {
override fun onFailure(call: Call<RefundListPOJODataClass>, t: Throwable) {
...
...
...
}
override fun onResponse(
call: Call<RefundListPOJODataClass>,
response: Response<RefundListPOJODataClass>
) {
binding.refundProgressBar.visibility = View.GONE
binding.rvRefundList.adapter =
response.body()?.let { RefundListAdapter(it, this#RefundListFragment) }
fun filterString(text: String) {
val filteredList: List<RefundListPOJODataClass> = ArrayList()
for (item in response.body()?.data!!) {
if (item != null) {
if (item.buyerName?.toLowerCase()?.contains(text.toLowerCase())!!) {
filteredList.add(item)
}
}
}
adapter.filterList(filteredList)
}
binding.refundListSearchBar.addTextChangedListener(object : TextWatcher {
override fun afterTextChanged(s: Editable?) {
filterString(s.toString())
}
override fun beforeTextChanged(s: CharSequence?, start: Int, count: Int, after: Int) {
}
override fun onTextChanged(s: CharSequence?, start: Int, before: Int, count: Int) {
}
})
}
})
}
However it returned an error:
Unresolved reference: add
This is the recyclerview Adapter:
RefundListAdapter.kt
class RefundListItemHolder(itemView: View) : RecyclerView.ViewHolder(itemView) {
private val refundedOrderId: TextView = itemView.refundedOrderId
private val orderDateTime: TextView = itemView.orderDateTime
private val refundedCustomerName: TextView = itemView.refundedCustomerName
fun bind(
refundHistory: RefundListPOJODataClassDataItem,
clickListener: RefundListOnItemClickListener
) {
refundedOrderId.text = refundHistory.orderId
orderDateTime.text = refundHistory.orderDate
refundedCustomerName.text = refundHistory.buyerName
itemView.setOnClickListener {
clickListener.onItemClicked(refundHistory)
}
}
}
class RefundListAdapter(
private var refundList: RefundListPOJODataClass,
private val itemClickListener: RefundListOnItemClickListener
) : RecyclerView.Adapter<RefundListItemHolder>() {
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): RefundListItemHolder {
val v = LayoutInflater.from(parent.context)
.inflate(R.layout.refund_list_item_layout, parent, false)
return RefundListItemHolder(v)
}
override fun getItemCount(): Int {
if (refundList.data != null) {
return refundList.data!!.size
} else {
return 0
}
}
override fun onBindViewHolder(holder: RefundListItemHolder, position: Int) {
val refundHistory = refundList.data?.get(position)
if (refundHistory != null) {
holder.bind(refundHistory, itemClickListener)
}
}
fun filterList(filteredList: List<RefundListPOJODataClass>) { //This is the function I called in the fragment
refundList = filteredList.get(0)
notifyDataSetChanged()
}
}
interface RefundListOnItemClickListener {
fun onItemClicked(refundHistory: RefundListPOJODataClassDataItem)
}
And this is how the data class looks like
RefundListPOJODataClass.kt
data class RefundListPOJODataClass(
#field:SerializedName("data")
val data: List<RefundListPOJODataClassDataItem?>? = null,
#field:SerializedName("error")
val error: Error? = null
)
data class RefundListPOJODataClassError(
#field:SerializedName("msg")
val msg: String? = null,
#field:SerializedName("code")
val code: Int? = null,
#field:SerializedName("status")
val status: Boolean? = null
)
data class RefundListPOJODataClassDataItem(
#field:SerializedName("order_date")
val orderDate: String? = null,
#field:SerializedName("buyer_name")
val buyerName: String? = null,
#field:SerializedName("phone_number")
val phoneNumber: String? = null,
#field:SerializedName("status_refund")
val statusRefund: String? = null,
#field:SerializedName("order_id")
val orderId: String? = null,
#field:SerializedName("refund")
val refund: Int? = null,
#field:SerializedName("refund_date")
val refundDate: String? = null
)
I want to search the recyclerview item by the attribute buyerName. How can I achieve it ? What should i change in my code? If there's any detail I missed to tell, Just let me know.
Your filtered list is of type List, which is immutable.
Change it to array list or MutableList:
val filteredList: ArrayList<RefundListPOJODataClass> = ArrayList()

Categories

Resources