RecyclerVIew onCreateViewHolder and onBindViewHolder is not called - android

I'm having two fragments
1.UploadFragment - to upload data to firestore
2.FetchFragemnt - fetch data from firestore and display it in recyclerView
these two fragments are used in a NavigationDrawer.
My problem is in fetchFragment initially recyclerView displays datas that are fetched from firestore.
but when I navigate to UploadFragment and return back to FetchFragment RecyclerView is not loaded.
Also, onCreateViewHolder and onBindViewHolder are not called when I navigate to UploadFragment and return back to FetchFragment.
Please someone help.
FetchFragment code :
class FetchFragment : Fragment(R.layout.fragment_fetch) {
private lateinit var binding : FragmentFetchBinding
private lateinit var adapter: PersonsAdapter
private lateinit var personsList: MutableList<PersonsDb>
private val personCollectionRef = Firebase.firestore.collection("persons")
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState)
binding = FragmentFetchBinding.bind(view)
personsList = mutableListOf()
adapter = PersonsAdapter(personsList){item ->
Intent(requireContext(),UpdateActivity::class.java).also{
it.putExtra("EXTRA_DETAILS",item.id)
startActivity(it)
}
}
binding.rvPersons.adapter = adapter
binding.rvPersons.layoutManager = LinearLayoutManager(requireContext())
fetchPPerson()
binding.svFilter.setOnQueryTextListener(object : SearchView.OnQueryTextListener {
override fun onQueryTextSubmit(p0: String?): Boolean {
//Performs search when user hit the search button on the keyboard
// adapter.getFilter().filter(p0);
return false
}
override fun onQueryTextChange(p0: String?): Boolean {
//Start filtering the list as user start entering the characters
adapter.getFilter().filter(p0);
return false
}
})
}
private fun fetchPPerson() = CoroutineScope(Dispatchers.IO).launch{
try{
val querySnapshot = personCollectionRef.get().await()
personsList.clear()
for(document in querySnapshot.documents){
val person = document.toObject<Person>()
personsList.add(
PersonsDb(document.id,
person?.name.toString(),
person?.age.toString().toInt(),
Date(person?.dob.toString())
))
}
withContext(Dispatchers.Main){
adapter.notifyDataSetChanged()
}
}catch (e:Exception){
withContext(Dispatchers.Main){
Toast.makeText(requireContext(),e.message, Toast.LENGTH_LONG).show()
Log.d("Fetch Error", e.message)
}
}
}
}
My Recycler Adapter :
class PersonsAdapter (
var persons : List<PersonsDb>,
private val listener: (PersonsDb) -> Unit
):RecyclerView.Adapter<PersonsAdapter.PersonsViewHolder>(),Filterable{
var personsList = persons
inner class PersonsViewHolder(val binding : ItemPersonBinding):
RecyclerView.ViewHolder(binding.root)
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): PersonsViewHolder {
val binding = ItemPersonBinding.inflate(LayoutInflater.from(parent.context),parent,false)
return PersonsViewHolder(binding)
}
override fun getItemCount(): Int {
return persons.size
}
override fun getFilter(): Filter {
return filter
}
override fun onBindViewHolder(holder: PersonsViewHolder, position: Int) {
val item = persons[position]
with(holder){
with(persons[position]){
binding.tvName.text = this.name
binding.tvAge.text = this.age.toString()
// binding.tvDob.text = this.dob.toString()
binding.tvDob.text = updateDateInView(this.dob)
}
}
holder.itemView.setOnClickListener { listener(item) }
}
private fun updateDateInView(cal : Date) : String{
val myFormat = "dd/MM/yyyy" // mention the format you need
val sdf = SimpleDateFormat(myFormat, Locale.US)
// binding.dpDob.setText(sdf.format(cal.getTime()))
return sdf.format(cal.getTime())
}
private val filter: Filter = object : Filter() {
override fun performFiltering(constraint: CharSequence): FilterResults {
var filteredList: MutableList<PersonsDb> = arrayListOf()
if (constraint.isEmpty()) {
filteredList.addAll(personsList)
} else {
val filterPattern = constraint.toString().toLowerCase().trim { it <= ' ' }
for (item in 0..persons.size -1) {
if (persons[item].name.toLowerCase().contains(filterPattern)
|| persons[item].age.toString().contains(filterPattern)) {
filteredList.add(persons[item])
}
}
}
val results = FilterResults()
results.count = filteredList.size
results.values = filteredList
// Log.d("Filter Values", results.values.toString())
return results
}
override fun publishResults(charSequence: CharSequence, filterResults: FilterResults) {
persons = if(filterResults == null || filterResults.values == null){
personsList
}
else
filterResults.values as List<PersonsDb>
notifyDataSetChanged()
}
}
}

Can you check Item count( log item count ) . That way you will know if data exists
for recyclerview when returning to FetchFragment . I suspect empty data could be reason.

Related

SearchView in Not Working in Recycler View

I'm trying to add searchview on recyclerview but its not working even not showing any error. I ready many answers on stackoverflow but they are not worked for me.please tell me what is mistake in my code. when i debug my code then searched values are showing in result variable but not showing in recyclerview. i want to search with 1) Country Name 2) capital 3) and id can some help me
my adapter is here
class ProfileListAdapter(var profiles:ArrayList<Profile>):RecyclerView.Adapter<ProfileListAdapter.ProfileViewHolder>(),Filterable {
fun updateProfile(newProfiles:List<Profile>){
profiles.clear()
profiles.addAll(newProfiles)
notifyDataSetChanged()
}
var profileFilterList = ArrayList<Profile>()
init {
profileFilterList = profiles
}
class ProfileViewHolder(view: View):RecyclerView.ViewHolder(view){
private var id = view.findViewById<TextView>(R.id.tv_id)
private var name = view.findViewById<TextView>(R.id.tv_name)
private var fatherName = view.findViewById<TextView>(R.id.tv_father_name)
private var profileImage = view.findViewById<ImageView>(R.id.iv_profile_image)
private var progressDrawable = getProgressDrawable(view.context)
fun bind(profile: Profile){
id.text = profile.id.toString()
name.text = profile.name
fatherName.text = profile.fatherName
profileImage.loadImage(profile.profilePicture,progressDrawable)
}
}
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int) = ProfileViewHolder(
LayoutInflater.from(parent.context).inflate(R.layout.rv_dummy_items,parent,false)
)
override fun onBindViewHolder(holder: ProfileViewHolder, position: Int) {
holder.bind(profiles[position])
}
override fun getItemCount() = profiles.size
// Search items
override fun getFilter(): Filter {
return object : Filter() {
override fun performFiltering(constraint: CharSequence?): FilterResults {
val charString = constraint?.toString() ?: ""
if (charString.isEmpty()){
profiles.also { profileFilterList = it }
} else {
val filteredList = ArrayList<Profile>()
profiles
.filter {
(it.name.contains(constraint!!)) or (it.fatherName.contains(constraint))
}
.forEach { filteredList.add(it) }
profileFilterList = filteredList
}
return FilterResults().apply { values = profileFilterList }
}
override fun publishResults(constraint: CharSequence?, results: FilterResults?) {
profileFilterList = if (results?.values == null) ArrayList()
else
results.values as ArrayList<Profile>
notifyDataSetChanged()
}
}
}
}
my main activity is here
class MainActivity : AppCompatActivity() {
lateinit var binding: ActivityMainBinding
lateinit var viewModel: ListViewModel
var profileAdapter = ProfileListAdapter(arrayListOf())
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
binding = ActivityMainBinding.inflate(layoutInflater)
val view = binding.root
setContentView(view)
//here I'm calling search profile function
searchProfile()
//
viewModel = ViewModelProviders.of(this).get(ListViewModel::class.java)
viewModel.refresh()
binding.rvProfileList.apply {
layoutManager = LinearLayoutManager(context)
adapter = profileAdapter
}
observeViewModel()
filterButtons()
}
fun observeViewModel() {
viewModel.profiles.observe(this, Observer { profiles: List<Profile>? ->
profiles?.let {
binding.rvProfileList.visibility = View.VISIBLE
profileAdapter.updateProfile(it)
}
})
viewModel.profileLoadingError.observe(this, Observer { isError: Boolean? ->
isError?.let {
binding.listError.visibility = if (it) View.VISIBLE else View.GONE
}
})
viewModel.loading.observe(this, Observer { isLoading ->
isLoading?.let {
binding.loadingView.visibility = if (it) View.VISIBLE else View.GONE
}
})
}
//search function
fun searchProfile(){
binding.searchView.setOnQueryTextListener(object: SearchView.OnQueryTextListener{
override fun onQueryTextSubmit(query: String?): Boolean {
profileAdapter.filter.filter(query)
return false
}
override fun onQueryTextChange(newText: String?): Boolean {
profileAdapter.filter.filter(newText)
return false
}
})
}
}
Your code quality is really bad. I read repeatly to understand what you mean.
Firstly, you are filtering twice in OnQueryTextListener. Instead you can filter once only. Change your searchProfile function to
fun searchProfile(){
binding.searchView.setOnQueryTextListener(object: SearchView.OnQueryTextListener{
override fun onQueryTextSubmit(query: String?): Boolean {
return false
}
override fun onQueryTextChange(newText: String?): Boolean {
profileAdapter.filter.filter(newText)
return false
}
})
}
Probably, your failure is because of reassigning your profiles and profileFilterList lists.
In few times, you are assingning profiles to profileFilterList, not copying! Both of two lists have same references. So if one of them changes, other list changes directly.
Change your Adapter init block from
init {
profileFilterList = profiles
}
to
init {
profileFilterList = ArrayList(profiles)
}
Change your getFilter function from
override fun getFilter(): Filter {
return object : Filter() {
override fun performFiltering(constraint: CharSequence?): FilterResults {
val charString = constraint?.toString() ?: ""
if (charString.isEmpty()){
profiles.also { profileFilterList = it }
} else {
val filteredList = ArrayList<Profile>()
profiles
.filter {
(it.name.contains(constraint!!)) or (it.fatherName.contains(constraint))
}
.forEach { filteredList.add(it) }
profileFilterList = filteredList
}
return FilterResults().apply { values = profileFilterList }
}
override fun publishResults(constraint: CharSequence?, results: FilterResults?) {
profileFilterList = if (results?.values == null) ArrayList()
else
results.values as ArrayList<Profile>
notifyDataSetChanged()
}
}
}
to
override fun getFilter(): Filter {
return object : Filter() {
override fun performFiltering(constraint: CharSequence?): FilterResults {
val filteredList = mutableListOf<Profile>()
if (constraint == null || constraint.isEmpty()) {
filteredList.addAll(profiles)
} else {
filteredList.addAll(
profiles.filter { (it.name.contains(constraint!!)) or (it.fatherName.contains(constraint)) } )
}
return FilterResults().apply { values = filteredList }
}
override fun publishResults(constraint: CharSequence?, results: FilterResults?) {
profileFilterList.clear()
results?.values?.let {
profileFilterList.addAll(it as MutableList<Profile>)
}
notifyDataSetChanged()
}
}
}
I edit in your adapter and filter works fine with me my code after modification
class ProfileListAdapter():RecyclerView.Adapter<ProfileListAdapter.ProfileViewHolder>(),Filterable {
var profileList: ArrayList<Profile> = ArrayList()
var profileListFiltered: ArrayList<Profile> = ArrayList()
fun updateProfile(newProfiles:List<Profile>){
profileList = ArrayList(newProfiles)
profileListFiltered = profileList
notifyDataSetChanged()
}
class ProfileViewHolder(view: View):RecyclerView.ViewHolder(view){
private var id = view.findViewById<TextView>(R.id.tv_id)
private var name = view.findViewById<TextView>(R.id.tv_name)
private var fatherName = view.findViewById<TextView>(R.id.tv_father_name)
private var profileImage = view.findViewById<ImageView>(R.id.iv_profile_image)
private var progressDrawable = getProgressDrawable(view.context)
fun bind(profile: Profile){
id.text = profile.id.toString()
name.text = profile.name
fatherName.text = profile.fatherName
profileImage.loadImage(profile.profilePicture,progressDrawable)
}
}
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int) =
ProfileViewHolder(
LayoutInflater.from(parent.context).inflate(R.layout.rv_dummy_items,parent,false)
)
override fun onBindViewHolder(holder: ProfileViewHolder, position: Int)
{
holder.bind(profileListFiltered[position])
}
override fun getItemCount() = profileListFiltered.size
// Search items
override fun getFilter(): Filter {
return object : Filter() {
override fun performFiltering(constraint: CharSequence?): FilterResults
{
val charString = constraint?.toString() ?: ""
if (charString.isEmpty()){
profileListFiltered = profileList
} else {
val filteredList = ArrayList<Profile>()
profileList
.filter {
(it.name.contains(constraint!!)) or
(it.fatherName.contains(constraint))
}
.forEach { filteredList.add(it) }
profileFilterList = filteredList
}
return FilterResults().apply { values = profileFilterList }
}
override fun publishResults(constraint: CharSequence?, results:
FilterResults?) {
profileFilterList = if (results?.values == null) ArrayList()
else
results.values as ArrayList<Profile>
notifyDataSetChanged()
}
}
}
}
in your activity just declare adapter without parameters constructor after get data using function inside adapter updateProfile then will work fine with you ISA
Edit for your adapter
class ProfileListAdapter(var
profiles:ArrayList<Profile>)
:RecyclerView.Adapter<ProfileListAdapter.Profile
ViewHolder>(),Filterable {
fun updateProfile(newProfiles:List<Profile>){
profiles.clear()
profiles.addAll(newProfiles)
notifyDataSetChanged()
}
var profileFilterList = ArrayList<Profile>()
init {
profileFilterList = profiles
}
class ProfileViewHolder(view: View):RecyclerView.ViewHolder(view){
private var id = view.findViewById<TextView>(R.id.tv_id)
private var name = view.findViewById<TextView>(R.id.tv_name)
private var fatherName = view.findViewById<TextView>
(R.id.tv_father_name)
private var profileImage = view.findViewById<ImageView>
(R.id.iv_profile_image)
private var progressDrawable = getProgressDrawable(view.context)
fun bind(profile: Profile){
id.text = profile.id.toString()
name.text = profile.name
fatherName.text = profile.fatherName
profileImage.loadImage(profile.profilePicture,progressDrawable)
}
}
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int) =
ProfileViewHolder(
LayoutInflater.from(parent.context)
.inflate(R.layout.rv_dummy_items,parent,false)
)
override fun onBindViewHolder(holder: ProfileViewHolder, position:
Int)
{
holder.bind(profileFilterList[position])
}
override fun getItemCount() = profileFilterList.size
// Search items
override fun getFilter(): Filter {
return object : Filter() {
override fun performFiltering(constraint: CharSequence?):
FilterResults {
val charString = constraint?.toString() ?: ""
if (charString.isEmpty()){
profileFilterList = profiles
} else {
val filteredList = ArrayList<Profile>()
profiles
.filter {
(it.name.contains(constraint!!)) or
(it.fatherName.contains(constraint))
}
.forEach { filteredList.add(it) }
profileFilterList = filteredList
}
return FilterResults().apply { values = profileFilterList }
}
override fun publishResults(constraint: CharSequence?, results:
FilterResults?) {
profileFilterList = if (results?.values == null) ArrayList()
else
results.values as ArrayList<Profile>
notifyDataSetChanged()
}
}
}
}

Recyclerview is not showing any items after filter results are set

I had to remade ArrayAdapter with filter feature to RecyclerView Adapter because of nested scrolling issues. But after I remade it, RecyclerView is empty, but adapter.itemCount is returning right value. Problem is that after I call adapter.notifyDataSetChanged(), it is not calling onCreateViewHolder or onBindViewHolder function.
class ZoneViewHolder(val root: ViewGroup): RecyclerView.ViewHolder(root) {
fun bind(
zone: FlightZone,
manageZoneCheck: (View)-> Unit,
maybeAutoselectZone: (View) -> Unit){
root.setOnClickListener {
manageZoneCheck(root.find(R.id.check))
}
root.find<View>(R.id.check).also { check->
check.setOnClickListener {
manageZoneCheck(check)
}
//autoselect zone if it was previously picked (after search reset)
maybeAutoselectZone(check)
}
root.findText(R.id.zoneNum).text = zone.name
root.findText(R.id.zoneName).apply {
isSelected = true
text = zone.radarInfo
}
root.findText(R.id.separator).setVisibleNotGone(zone.radarInfo != null)
}
}
class ZoneListAdapter(
private val ctx: Context,
private val inflater: LayoutInflater,
private val zoneView: Int,
private val zoneList: List<FlightZone>,
private var list: MutableList<FlightZone>,
private val pickedZones: List<FlightZone>,
private val onZoneChecked: (FlightZone, Boolean) -> Unit,
private val onAllZonesChecked: (Boolean) -> Unit,
private val onFilterDone: (List<FlightZone>) -> Unit
): RecyclerView.Adapter<ZoneViewHolder>(), Filterable{
override fun getItemCount() = list.size
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): ZoneViewHolder {
return ZoneViewHolder(inflater.inflate(zoneView, parent, false) as ViewGroup)
}
override fun onBindViewHolder(vh: ZoneViewHolder, position: Int) {
val zone = list[position]
App.log("ZoneListAdapter: onBindView: ${list.size}")
vh.bind(
zone,
manageZoneCheck = { check->
manageZoneCheck(check, zone)
},
maybeAutoselectZone = {check->
App.log("ZoneListAdapter: alreadyPicked: ${pickedZones.size}")
if (pickedZones.find { it.id == zone.id } != null) check.callOnClick()
}
)
}
/**
* Custom Filter implementation for custom suggestions we provide.
*/
data class ZoneFilterable(val zone: FlightZone, val prefixLength: Int)
internal var tempItems: MutableList<FlightZone> = zoneList.toMutableList()
internal var suggestions: MutableList<ZoneFilterable> = mutableListOf()
internal val sharedCounterLock = Semaphore(1)
private var filter = object : Filter(){
override fun performFiltering(constraint: CharSequence?): FilterResults {
return if (constraint != null) {
sharedCounterLock.acquire()
suggestions.clear()
filterByName(constraint)
suggestions.sortedByDescending { it.prefixLength }
val filterResults = FilterResults()
filterResults.values = suggestions
filterResults.count = suggestions.size
sharedCounterLock.release()
filterResults
} else {
FilterResults()
}
}
private fun filterByName(constraint: CharSequence?){
tempItems.forEach {
val zoneName = it.name.toLowerCase(Locale.getDefault())
val zoneNameNonAccent = zoneName.removeDiacritics()
val query = constraint.toString().toLowerCase(Locale.getDefault())
val queryNonAccent = query.removeDiacritics()
App.log("FlightZonePicker filter zone name non-accent: $zoneNameNonAccent")
if (zoneNameNonAccent.contains(queryNonAccent)) {
val prefix = zoneName.commonPrefixWith(query)
suggestions.add(ZoneFilterable(it, prefix.length))
}
}
}
override fun publishResults(constraint: CharSequence?, results: FilterResults) {
if (results.count > 0) {
list.clear()
val filterList = results.values as? List<Any?>
var resultList = mutableListOf<FlightZone>()
GlobalScope.launch(Dispatchers.Main) {
val resultListAsync = async {
withContext(Dispatchers.Default) {
val list = mutableListOf<FlightZone>()
sharedCounterLock.acquire()
val iter = filterList?.iterator()
iter?.let {
while (iter.hasNext()) {
val item = iter.next()
(item as ZoneFilterable).let { (zoneEntity) -> list.add(zoneEntity) }
}
}
sharedCounterLock.release()
return#withContext list
}
}
resultList = resultListAsync.await().take(10).toMutableList()
App.log("ZoneListAdapter: Results: ${resultList.size}")
list.addAll(resultList)
onFilterDone.invoke(resultList)
}
}
}
}
init {
tempItems = zoneList.toMutableList()
}
override fun getFilter(): Filter {
return filter
}
}
MainClass:
zoneListRecycleView = findViewById(R.id.zoneResults)
zoneListAdapter = ZoneListAdapter(
ctx,
f.layoutInflater,
R.layout.zone_pick_item,
zoneList,
filteredZones,
pickedZones,
onZoneChecked = {
zone, isPicked ->
pickedZones.apply {
if (isPicked){
if (find { it.id == zone.id } == null) add(zone)
} else {
if (find { it.id == zone.id } != null) remove(zone)
}
}
zoneListAdapter.notifyDataSetChanged()
},
onAllZonesChecked = {ischecked->
pickedZones.apply {
clear()
if(ischecked) addAll(zoneList)
}
zoneListAdapter.notifyDataSetChanged()
},
::onFilterResult
)
zoneListRecycleView.adapter = zoneListAdapter
private fun onFilterResult(list: List<FlightZone>){
filteredZones = list.toMutableList()
zoneListAdapter.notifyDataSetChanged()
App.log("ZonelistAdapter: count = ${zoneListAdapter.itemCount}")
}
UPDATE:
I changed Adapter to ListAdapter and I changed publishResults function to
resultList = resultListAsync.await().take(10).toMutableList()
onFilterDone.invoke(resultList)
And inside my parent class I call:
private fun onFilterResult(list: List<FlightZone>){
filteredZones = list.toMutableList()
zoneListAdapter.submitList(filteredZones)
App.log("ZonelistAdapter: filteredList = ${filteredZones.size}")
App.log("ZonelistAdapter: count = ${zoneListAdapter.itemCount}")
}
Log:
app: ZonelistAdapter: filteredList = 10
app: ZonelistAdapter: count = 0
There is still some issue with adapter. So filter feature is working as intended but adapter and recyclerview is not displaying items for some reason.

Android Kotlin: How can I delete the data from Firebase

I am a new about Android Kotlin. I try to delete the data from Cloud Firebase when I click the button on my app. I did some necessary code on my adapter but How can ı call the database collection on my Activity? ı shared the my adapter and my Activity code below.
class NoteAdapter(val titleText: ArrayList<String>, val rowImage: ArrayList<String>, val noteText: ArrayList<String>, val listener: onClick) : RecyclerView.Adapter<NoteAdapter.NoteHolder>() {
interface onClick {
fun onItemClickListener(v: View, pos: Int, data: Any)
}
class NoteHolder(itemView: View) : RecyclerView.ViewHolder(itemView) {
val itemImage : ImageView = itemView.findViewById(R.id.recyclerImage)
val itemDelete: ImageView = itemView.findViewById(R.id.delete)
}
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): NoteHolder {
val v = LayoutInflater.from(parent.context).inflate(R.layout.recycler_row, parent, false)
return NoteHolder(v)
}
override fun onBindViewHolder(holder: NoteHolder, position: Int) {
holder.itemView.recyclerTitleText.text = titleText[position]
Picasso.get().load(rowImage[position]).resize(150,150).into(holder.itemImage)
holder.itemView.setOnClickListener {
val intent = Intent(holder.itemView.context, PastNotesActivity:: class.java)
intent.putExtra("oldTitle", titleText[position])
intent.putExtra("oldNote", noteText[position])
intent.putExtra("oldImage", rowImage[position])
holder.itemView.context.startActivity(intent)
}
holder.itemDelete.setOnClickListener { v: View ->
titleText.removeAt(position)
noteText.removeAt(position)
rowImage.removeAt(position)
notifyItemRemoved(position)
listener.onItemClickListener(v, position, holder.itemView)
}
}
override fun getItemCount(): Int {
return titleText.size
}
override fun getItemId(position: Int):Long {
return position.toLong()
}
override fun getItemViewType(position: Int):Int {
return position
}
}
And This is my Activity code, I create the itemDelete fun in this Activity but How can I define my adapter code in this fun? and I tried to write "{id.data}" in my document but did not work what should I write ?
class ListViewActivity : AppCompatActivity() {
var selectedPicture: Uri? = null
private lateinit var auth: FirebaseAuth
private lateinit var db : FirebaseFirestore
var titleTextFromFB : ArrayList<String> = ArrayList()
var noteTextFromFB : ArrayList<String> = ArrayList()
var imageFromFB : ArrayList<String> = ArrayList()
var adapter: NoteAdapter? = null
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_list_view)
auth = FirebaseAuth.getInstance()
db = FirebaseFirestore.getInstance()
getDataFromFirestore()
// recyclerview
var layoutManager = LinearLayoutManager(this)
recyclerView.layoutManager = layoutManager
// adapter = NoteAdapter(titleTextFromFB, imageFromFB, noteTextFromFB)
//recyclerView.adapter = adapter
adapter = NoteAdapter(titleTextFromFB, imageFromFB, noteTextFromFB, object: NoteAdapter.onClick{
override fun onItemClickListener(v: View, pos: Int, data: Any) {
when(v.id){
R.id.delete -> itemDelete(data)
}
}
})
recyclerView.adapter = adapter
}
override fun onCreateOptionsMenu(menu: Menu?): Boolean {
val menuInflater = menuInflater
menuInflater.inflate(R.menu.add_note, menu)
return super.onCreateOptionsMenu(menu)
}
override fun onOptionsItemSelected(item: MenuItem): Boolean {
if (item.itemId == R.id.add_note_click) {
// Take Notes Activity
val intent = Intent(applicationContext, TakeNotesActivity::class.java)
intent.putExtra("info","new")
startActivity(intent)
} else if (item.itemId == R.id.log_out) {
val alert = AlertDialog.Builder(this)
alert.setTitle("Log Out")
alert.setMessage("Are you sure to logout from the app ?")
alert.setPositiveButton("Yes") {dialog, which ->
auth.signOut()
val intent = Intent(applicationContext, MainActivity::class.java)
startActivity(intent)
finish()
}
alert.setNegativeButton("No") {dialog, which ->
}
alert.show()
}
return super.onOptionsItemSelected(item)
}
// get data from firestore
fun getDataFromFirestore() {
db.collection("Notes").orderBy("date", Query.Direction.DESCENDING).addSnapshotListener{ snapshot, exception ->
if (exception != null) {
// If there is a error ,
Toast.makeText(applicationContext, exception.localizedMessage.toString(), Toast.LENGTH_LONG).show()
} else {
if (snapshot != null) {
if (!snapshot.isEmpty) {
titleTextFromFB.clear()
noteTextFromFB.clear()
imageFromFB.clear()
val documents = snapshot.documents
for (document in documents) {
val userEmail = document.get("userEmail") as String
val noteTitle = document.get("noteTitle") as String
val yourNote = document.get("yourNote") as String
val downloadUrl = document.get("downloadUrl") as String
val timestamp = document.get("date") as Timestamp
val date = timestamp.toDate()
titleTextFromFB.add(noteTitle)
imageFromFB.add(downloadUrl)
noteTextFromFB.add(yourNote)
adapter!!.notifyDataSetChanged()
}
}
}
}
}
}
fun itemDelete(data: Any) {
db.collection("Notes").document().delete().addOnSuccessListener {
}
.addOnFailureListener { exception ->
Toast.makeText(applicationContext, exception.localizedMessage.toString(), Toast.LENGTH_LONG).show()
}
}
}
This code won't work:
db.collection("Notes").document().delete().addOnSuccessListener {
The db.collection("Notes").document() call creates a reference to a new document, which you then delete. So nothing happens.
What you need to do is determine the ID of the document that the user clicked on, and pass that into the document(...) call. That gives you a DocumentReference to the correct document, so that the delete() call will then delete that document.
The key to determining the ID of the document the user clicked on is in this code:
adapter = NoteAdapter(titleTextFromFB, imageFromFB, noteTextFromFB, object: NoteAdapter.onClick{
override fun onItemClickListener(v: View, pos: Int, data: Any) {
when(v.id){
R.id.delete -> itemDelete(data)
}
}
})
You will need to determine the ID from one of these parameters: v, post, or data. I typically do this by keeping a list of document IDs or DocumentSnapshot objects in my adapter or activity, and then looking the clicked item up by its position/index.
So in your getDataFromFirestore function, add the snapshots to a list that you've defined as a field in your activity class:
// in your activity, declare a list;
var mDocuments: List<DocumentSnapshot>? = null
// Then in getDataFromFirestore store that list
...
mDocuments = snapshot.documents;
val documents = snapshot.documents
for (document in documents) {
...
}
...
// And use it when calling itemDelete:
adapter = NoteAdapter(titleTextFromFB, imageFromFB, noteTextFromFB, object: NoteAdapter.onClick{
override fun onItemClickListener(v: View, pos: Int, data: Any) {
when(v.id){
R.id.delete -> itemDelete(mDocuments[pos])
}
}
})
// To then finally delete the document by its ID
fun itemDelete(doc: DocumentSnapshot) {
db.collection("Notes").document(doc.Id).delete()
}

how to filter list data in descending order in kotlin?

From the Android app, I wrote for I want to add, add a button in the toolbar that acts as a toggle. When the toggle is disabled (the default state) all posts should be shown, when it is enabled (after a tap) the list should only show the posts having user_id set to 1 and sorted by descending published_at. Tapping on the button again will return it to its default state.
Note that publishedAt returning date and publishedAt and user_id coming from postList from the server I want to know how can I implement above requirement what kind of steps should I have to follow
below my logic implementation in MainActivity.kt
class MainActivity : AppCompatActivity() {
#Inject
lateinit var restInterface: RestInterface
private fun initializeDagger() = App.appComponent.inject(this)
var context: Context? = null
private var filteredList: List<Post>? = null
private var recyclerView: RecyclerView? = null
private var switch1: Switch? = null
private var restAdapter: RestAdapter? = null
private var postList: List<Post>? = null
private var restList: RestList? = null
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
initializeDagger()
recyclerView = findViewById(R.id.recycler_view)
switch1 = findViewById(R.id.switch1)
fetchPosts()
switch1.setOnclickListener {
postList.forEach { postItem: Post ->
if (postItem.userId == 1)
filteredList.add(postItem)
}
recyclerView.post = filteredList
recyclerView.notifyDatasetChanged()
}
// Collections.sort( filteredList.get(4).publishedAt, Collections.reverseOrder());
}
private fun fetchPosts() {
val progress = ProgressDialog(this)
progress.setMessage("Loading... ")
progress.isIndeterminate = true
progress.show()
restInterface?.getPosts?.subscribeOn(Schedulers.newThread())
.observeOn(AndroidSchedulers.mainThread())
.subscribe(object : DisposableSingleObserver<Response<RestList>>() {
override fun onSuccess(response: Response<RestList>) {
restList = response.body()
val layoutManager = LinearLayoutManager(applicationContext)
recyclerView?.layoutManager = layoutManager
// initialize postList with posts
postList = restList?.posts
restAdapter = postList?.let { RestAdapter(it, restList) }
recyclerView?.adapter = restAdapter
}
override fun onError(e: Throwable) {
progress.dismiss()
Toast.makeText(context, "" + e.message, Toast.LENGTH_SHORT).show()
}
})
}
}
below my RestAdapter.kt
class RestAdapter(val post: List<Post>,val restList: RestList?) : RecyclerView.Adapter<RestAdapter.PostHolder>() {
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): PostHolder {
val itemView = LayoutInflater.from(parent.context).inflate(R.layout.post_list, null)
return PostHolder(itemView)
}
override fun getItemCount(): Int {
return post.size
}
override fun onBindViewHolder(holder: PostHolder, position: Int) {
val posts = post[position]
Picasso
.get() // give it the context
.load(posts.image) // load the image
.into(holder.postImage)
holder.userId.text = posts.userId.toString()
holder.postTitle.text = posts.title
holder.postTime.text = posts.publishedAt
holder.postDescription.text = posts.description
}
class PostHolder(itemView: View) : RecyclerView.ViewHolder(itemView) {
val postImage: ImageView = itemView.findViewById(R.id.postImage)
val userId: TextView = itemView.findViewById(R.id.userId)
val postTitle: TextView = itemView.findViewById(R.id.postTitle)
val postTime: TextView = itemView.findViewById(R.id.postTime)
val postDescription: TextView = itemView.findViewById(R.id.postDescription)
}
}
You can use method .sortedByDescending or .sortedBy on list :)
[Edit]
I give you a simple solution for that, maybe not the best but should work
1. Change RestAdapter constructor to (var post: List,val restList: RestList?)
Add method to updateData in apadapter:
fun filterData(isChecked: Boolean) {
if (isChecked) {
val filteredList = arrayListOf<Post>()
filteredList.addAll(restList?posts.filter { it.user_id == 1 }.sortedByDescending { it.published_at })
post = filteredList
} else {
post = restList?.posts
}
notifyDatasetChanged()
}
And in your class use this:
switch1.setOnclickListener {
restAdapter?.filterData(switch1.isChecked()//state of your switch i.e isChecked() which return true or false)
}

autocompletetextview suggestion does not appear when rewriting

I am currently learning Android programming and currently trying to make autocompletetextview by following the tutorial from the following link https://medium.com/#droidbyme/autocomplete-textview-in-android-a1bf5fc112f6 on this link I managed to bring up suggestions from the retrofit response but when I rewrote the suggestion it didn't appear.
this is from my activity
var adapter = SuggestionAdapter(this#Formpengiriman_Activity, R.layout.custom_row, kecamatanModel.getProducts()) autoCompleteTextView.setAdapter(adapter) autoCompleteTextView.setThreshold(1)
this is my kecamatanModel
class KecamatanModel {
private val kecamatan: ArrayList<Kecamatan>
init {
this.kecamatan = ArrayList<Kecamatan>()
var call: Call<List<GetKecamatan>> = ApiClient.getClient.showkecamatan()
call.enqueue(object : Callback<List<GetKecamatan>> {
override fun onFailure(call: Call<List<GetKecamatan>>, t: Throwable) {
}
override fun onResponse(
call: Call<List<GetKecamatan>>,
response: Response<List<GetKecamatan>>
) {
if(response.isSuccessful){
var json = response.body()
for(i in json?.indices!!){
kecamatan.add(Kecamatan(json.get(i).getIDKECAMATAN().toString(), json.get(i).getNAMAKECAMATAN().toString(), json.get(i).getNAMAPROVINSI().toString(), json.get(i).getNAMAKOTA().toString()))
}
}
}
})
}
fun getProducts(): ArrayList<Kecamatan> {
return this.kecamatan
} }
this is my SuggestionAdapter
class SuggestionAdapter(
internal val context: Context,
private val resourceId: Int,
items: ArrayList<Kecamatan>
) : ArrayAdapter<Kecamatan>(context, resourceId, items) {
private val items: List<Kecamatan>
private var tempItems: List<Kecamatan>
private var suggestions: MutableList<Kecamatan>
private val fruitFilter = object : Filter() {
override fun convertResultToString(resultValue: Any): CharSequence {
val fruit = resultValue as Kecamatan
return fruit.getNama().toString()
}
override fun performFiltering(charSequence: CharSequence?): Filter.FilterResults {
suggestions = ArrayList()
tempItems = ArrayList(items)
if (charSequence != null) {
suggestions.clear()
for (fruit in tempItems) {
if (fruit.getNama()?.toLowerCase()?.startsWith(charSequence.toString().toLowerCase())!!) {
suggestions.add(fruit)
}
}
val filterResults = Filter.FilterResults()
filterResults.values = suggestions
filterResults.count = suggestions.size
return filterResults
} else {
return Filter.FilterResults()
}
}
override fun publishResults(
charSequence: CharSequence?,
filterResults: Filter.FilterResults
) {
val tempValues = filterResults.values as ArrayList<Kecamatan>
if (filterResults != null && filterResults.count > 0) {
clear()
for (fruitObj in tempValues) {
add(fruitObj)
}
notifyDataSetChanged()
} else {
clear()
notifyDataSetChanged()
}
}
}
init {
this.items = items
tempItems = ArrayList(items)
suggestions = ArrayList()
for (i in 0 until items.size) {
suggestions!!.add(items[i])
}
}
override fun getView(position: Int, convertView: View?, parent: ViewGroup): View {
var view = convertView
try {
if (convertView == null) {
val inflater = LayoutInflater.from(context)
view = inflater.inflate(R.layout.custom_row, parent, false)
}
val fruit = getItem(position)
Log.d("kecamatan", fruit?.getNama())
val name = view?.findViewById(R.id.tv1) as TextView
name.setText(fruit!!.getprov()+", "+fruit!!.getkota()+", "+fruit!!.getNama())
} catch (e: Exception) {
e.printStackTrace()
}
return view!!
}
#Nullable
override fun getItem(position: Int): Kecamatan? {
return items[position]
}
override fun getCount(): Int {
return items.size
}
override fun getItemId(position: Int): Long {
return position.toLong()
}
override fun getFilter(): Filter {
return fruitFilter
}}

Categories

Resources