How to refresh a RecylcerView? - android

I need to develop an app from university.
When I start the app, the RecyclerView is displayed correctly. However, when I refresh the RecyclerView or switch to another TAP, the card layouts are no longer displayed.
I get all the events from Firebase using an Event data class and pass them to the RecyclerAdapter.
Can you help me so that the refresh works?
Thanks a lot
Augustin
RecyclerAdapter:
class RecyclerAdapter(val events: List<Event>) :
RecyclerView.Adapter<RecyclerAdapter.ViewHolder>() {
private lateinit var navController: NavController
private lateinit var events_id : String
var countEventId = mutableListOf<String>()
var count = 0
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): ViewHolder {
val view =
LayoutInflater.from(parent.context).inflate(R.layout.view_cardlayout, parent, false)
return ViewHolder(view)
}
override fun getItemCount() = events.size
override fun onBindViewHolder(holder: RecyclerAdapter.ViewHolder, position: Int) {
holder.bind(events[position])
}
inner class ViewHolder(itemView: View) : RecyclerView.ViewHolder(itemView) {
fun bind(event: Event) {
itemView.headlineTV.text = event.name
itemView.placeHolderTV.text = event.location
itemView.dateHolderTV.text = event.date
itemView.timeHolderTV.text = "${event.starttime} Uhr"
itemView.dataHolderVotes.text = event.votes.toString()
itemView.dataHolderVotes.text = event.votesUser?.size.toString()
countEventId.add(event.eventId)
count++
}
init {
itemView.setOnClickListener {
val pos: Int =
bindingAdapterPosition
navController = findNavController(itemView)
val action_HomeToData1 =
HomeFragmentDirections.actionHomeFragmentToData1Fragment(countEventId[pos])
navController.navigate(action_HomeToData1)
}
}
}
}
HomeFragment:
class HomeFragment : Fragment(R.layout.fragment_home) {
private lateinit var firestoneDb: FirebaseFirestore
private lateinit var events: MutableList<Event>
//private lateinit var adapter: RecyclerAdapter
private var layoutManager: RecyclerView.LayoutManager? = null
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState)
var auth = FirebaseAuth.getInstance()
var user = auth.currentUser
var uid = user?.uid
firestoneDb = FirebaseFirestore.getInstance()
events = mutableListOf()
recyclerView.adapter = RecyclerAdapter(events)
recyclerView.layoutManager = LinearLayoutManager(activity)
val eventsReference = firestoneDb.collection("events")
eventsReference
.whereEqualTo("creator", uid)
.addSnapshotListener { snapshot, exception ->
if (exception != null || snapshot == null) {
Log.e(TAG, "Exception when querying events", exception)
return#addSnapshotListener
}
var eventList = snapshot.toObjects(Event::class.java)
events.clear()
events.addAll(eventList)
for (event in eventList) {
Log.i(TAG, "Event ${event}")
}
}
refreshHome()
}
override fun onResume() {
super.onResume()
}
private fun refreshHome() {
refresherHome.setOnRefreshListener {
Toast.makeText(activity, "Page has been refreshed", Toast.LENGTH_SHORT).show()
refresherHome.isRefreshing = false
val action_HomeToSelf = HomeFragmentDirections.actionHomeFragmentSelf()
findNavController().navigate(action_HomeToSelf)
}
}
}
Data class Event:
data class Event (
var description: String = "",
#get: PropertyName("start_time") #set:PropertyName("start_time") var starttime: String = "",
var creator: String = "",
#get: PropertyName("event_id") #set:PropertyName("event_id")var eventId: String = "",
var location: String = "",
var name: String = "",
var questions: List<String>? = null,
var date: String = "",
#get: PropertyName("votes") #set:PropertyName("votes") var votes: Int = 0,
#get: PropertyName("creationTimeMs") #set:PropertyName("creationTimeMs")var creationTimeMs: Long = 0,
#get: PropertyName("votes_user") #set:PropertyName("votes_user")var votesUser: List<String>? = null
)

After you change the events in the list, you need to tell the adapter that its data has change so that it knows to refresh the view. To do this call adapter.notifyDataSetChanged(), inside the snapshot listener after you're done modifying events.

Related

Filter Images and RecyclerView OnItemClickListener

So i am trying 2 things here and it seems to be all right but i am not beeing able to reach my API response. First i want to Filter my API to All information, only Images and only Pdf.- and second to make a recyclerView OnItemClickListener. If you can help to provide me this error i will very graceful. Thank You .
//Main Activity
class MainActivity : AppCompatActivity() {
private lateinit var recyclerview_users: RecyclerView
private lateinit var imageList : ArrayList<ImageModel>
private lateinit var imageAdapter: ImageAdapter
private var imageModel: List<ImageModel> = mutableListOf()
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
val allButton = findViewById<Button>(R.id.button_all)
allButton.setOnClickListener {
getBlob()
}
val photoButton = findViewById<Button>(R.id.button_image)
photoButton.setOnClickListener {
filterImageModel("photo")
}
val pdfButton = findViewById<Button>(R.id.button_pdf)
pdfButton.setOnClickListener {
filterImageModel("pdf")
}
recyclerview_users = findViewById(R.id.recycler_view)
recyclerview_users.setHasFixedSize(true)
recyclerview_users.layoutManager = LinearLayoutManager(this)
imageList = ArrayList()
imageAdapter = ImageAdapter(imageModel)
recyclerview_users.adapter = imageAdapter
var layoutManager = GridLayoutManager(this, 3)
recyclerview_users.layoutManager = layoutManager
getBlob()
}
private fun getBlob(){
val plcApi = ServiceGenerator.buildService(PLCApi::class.java)
val call = plcApi.getBlob()
call.enqueue(object : Callback<MutableList<ImageModel>>{
override fun onResponse(
call: Call<MutableList<ImageModel>>,
response: Response<MutableList<ImageModel>>
){
if (response.isSuccessful){
imageModel = response.body()!!
imageAdapter.updateImageModel(imageModel)
val imageList = response.body()!! as ArrayList<ImageModel>
val imageAdapter = ImageAdapter(imageList)
recyclerview_users.adapter = imageAdapter
imageAdapter.setOnitemClickListener { imageModel ->
val intent = Intent(this#MainActivity, ImageInformation::class.java)
startActivity(intent)
}
}else{
Toast.makeText(this#MainActivity, "Failed to retrieve data, please try again", Toast.LENGTH_SHORT).show()
}
}
override fun onFailure(call: Call<MutableList<ImageModel>>, t: Throwable){
Toast.makeText(this#MainActivity, "Network error, please check your connection", Toast.LENGTH_SHORT).show()
}
})
}
private fun filterImageModel(contentType: String) {
val filteredImageModel = imageModel.filter {
it.contentType == contentType
}
imageModel = filteredImageModel
imageAdapter.updateImageModel(filteredImageModel)
}
}
//ImageAdapter
class ImageAdapter(private var imageModel: List<ImageModel>) : RecyclerView.Adapter<ImageAdapter.ImageViewHolder>() {
private var onItemClickListener: ((ImageModel) -> Unit)? = null
fun setOnitemClickListener(listener: (ImageModel) -> Unit){
onItemClickListener = listener
}
fun updateImageModel(newImageModel: List<ImageModel>){
imageModel = newImageModel
notifyDataSetChanged()
}
class ImageViewHolder(itemView: View): RecyclerView.ViewHolder(itemView){
var downloadUrl: TextView = itemView.findViewById(R.id.downloadUrl)
var previewUrl: ImageView = itemView.findViewById(R.id.previewUrl)
var id: TextView = itemView.findViewById(R.id.id)
var filename: TextView = itemView.findViewById(R.id.fileName)
var filesize: TextView = itemView.findViewById(R.id.filesize)
var contentType: TextView = itemView.findViewById(R.id.contentType)
var createdBy: TextView = itemView.findViewById(R.id.createdBy)
var createdTimestamp: TextView = itemView.findViewById(R.id.createdTimestamp)
var creationSource: TextView = itemView.findViewById(R.id.creationSource)
var domainIdentityType: TextView = itemView.findViewById(R.id.domainIdentityType)
var domainIdentityValue: TextView = itemView.findViewById(R.id.domainIdentityValue)
var tags: TextView = itemView.findViewById(R.id.tags)
var description: TextView = itemView.findViewById(R.id.description)
}
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): ImageViewHolder {
val view = LayoutInflater.from(parent.context).inflate(R.layout.layout_items, parent, false)
return ImageViewHolder(view)
}
#SuppressLint("CheckResult", "ResourceType")
override fun onBindViewHolder(holder: ImageViewHolder, position: Int) {
val imageId = imageModel[position]
holder.downloadUrl.text = imageId.downloadUrl
if (imageId.contentType!!.startsWith("image")){
Glide.with(holder.itemView.context).load(imageId.previewUrl).into(holder.previewUrl)
}else{
holder.previewUrl.setImageResource(R.drawable.pdf)
}
holder.id.text = imageId.id
holder.filename.text = imageId.fileName
holder.filesize.text = imageId.fileName.toString()
holder.contentType.text = imageId.contentType
holder.createdBy.text = imageId.createdBy
holder.createdTimestamp.text = imageId.createdTimestamp
holder.creationSource.text = imageId.creationSource
holder.domainIdentityType.text = imageId.domainIdentityType
holder.domainIdentityValue.text = imageId.domainIdentityValue
holder.tags.text = imageId.tags.toString()
holder.description.text = imageId.description
holder.itemView.setOnClickListener{
onItemClickListener?.invoke(imageId)
}
}
override fun getItemCount(): Int {
return imageModel.size
}
}
//ImageModel
data class ImageModel(
#SerializedName("downloadUrl")
var downloadUrl: String? = null,
#SerializedName("previewUrl")
val previewUrl: String? = null,
#SerializedName("id")
var id: String? = null,
#SerializedName("fileName")
val fileName: String? = null,
#SerializedName("filesize")
val filesize: Int,
#SerializedName("contentType")
val contentType: String? = null,
#SerializedName("createdBy")
val createdBy: String? = null,
#SerializedName("createdTimestamp")
val createdTimestamp: String? = null,
#SerializedName("creationSource")
val creationSource: String? = null,
#SerializedName("domainIdentityType")
val domainIdentityType: String? = null,
#SerializedName("domainIdentityValue")
val domainIdentityValue: String? = null,
#SerializedName("tags")
val tags: List<String>? = null,
#SerializedName("description")
val description: String? = null)
: Parcelable{
constructor(parcel: Parcel) : this(
parcel.readString()!!,
parcel.readString()!!,
parcel.readString()!!,
parcel.readString()!!,
parcel.readInt(),
parcel.readString()!!,
parcel.readString()!!,
parcel.readString()!!,
parcel.readString()!!,
parcel.readString()!!,
parcel.readString()!!,
parcel.createStringArrayList(),
parcel.readString()!!
)
override fun describeContents(): Int {
return 0
}
override fun writeToParcel(parcel: Parcel, flags: Int) {
parcel.writeString(downloadUrl)
parcel.writeString(previewUrl)
parcel.writeString(id)
parcel.writeString(fileName)
parcel.writeInt(filesize)
parcel.writeString(contentType)
parcel.writeString(createdBy)
parcel.writeString(createdTimestamp)
parcel.writeString(creationSource)
parcel.writeString(domainIdentityType)
parcel.writeString(domainIdentityValue)
parcel.writeString(tags.toString())
parcel.writeString(description)
}
companion object CREATOR : Parcelable.Creator<ImageModel> {
override fun createFromParcel(parcel: Parcel): ImageModel {
return ImageModel(parcel)
}
override fun newArray(size: Int): Array<ImageModel?> {
return arrayOfNulls(size)
}
}
}
//PLC API
interface PLCApi {
#GET("/BlobStorage/Blobs?StorageContainerId=ccef4ed7-7ec7-421d-8afb-3dce0a8be39c")
fun getBlob():Call<MutableList<ImageModel>>
}
//ServiceGenerator
object ServiceGenerator {
private val client = OkHttpClient.Builder().build()
private val retrofit = Retrofit.Builder()
.baseUrl("http://app-bbg-blob-assessment.azurewebsites.net/")
.addConverterFactory(GsonConverterFactory.create())
.client(client)
.build()
fun <T> buildService(service: Class<T>): T {
return retrofit.create(service)
}
}
//ImageInformation where i want to invoke the ClickListener
class ImageInformation : AppCompatActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_image_information)
val image = intent.getParcelableExtra<ImageModel>("ImageModel")
if (image != null){
val downloadUrl: TextView = findViewById(R.id.downloadUrla)
val previewUrl : ImageView = findViewById(R.id.previewUrla)
val id: TextView = findViewById(R.id.idsa)
val filename: TextView = findViewById(R.id.fileNamea)
val filesize: TextView = findViewById(R.id.filesizea)
val contentType: TextView = findViewById(R.id.contentTypea)
val createdBy: TextView = findViewById(R.id.createdBya)
val createdTimestamp: TextView = findViewById(R.id.createdTimestampa)
val creationSource: TextView = findViewById(R.id.creationSourcea)
val domainIdentityType: TextView = findViewById(R.id.domainIdentityTypea)
val domainIdentityValue: TextView = findViewById(R.id.domainIdentityValuea)
val tags: TextView = findViewById(R.id.tagsa)
val description: TextView = findViewById(R.id.descriptiona)
downloadUrl.text = image.downloadUrl
Glide.with(this).load(image.previewUrl).into(previewUrl)
id.text = image.id
filename.text = image.fileName
filesize.text = image.filesize.toString()
contentType.text = image.contentType
createdBy.text = image.createdBy
createdTimestamp.text = image.createdTimestamp
creationSource.text = image.creationSource
domainIdentityType.text = image.domainIdentityType
domainIdentityValue.text = image.domainIdentityValue
tags.text = image.tags.toString()
description.text = image.description
image.downloadUrl = downloadUrl.text as String?
image.id = id.text as String?
}
}
}

Why is the .update("field","value") not working?

If you see the read messages function in my activity class below, i wanted to update the isSeen field in firestore, but for some reason it does not work at all. My guess it requires a specific document value but that would not be possible as this a messaging app so there will be a lot of documents created.
Activity Class
class MessageActivity : AppCompatActivity() {
private lateinit var binding: ActivityMessageBinding
private lateinit var chat: ArrayList<Message>
private lateinit var messageAdapter: MessageAdapter
private lateinit var roomID: String
private lateinit var userID: String
private lateinit var recID: String
private var c: Int = 0
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
binding = ActivityMessageBinding.inflate(layoutInflater)
setContentView(binding.root)
userID = FirebaseAuth.getInstance().uid.toString()
recID = intent.getStringExtra("userID").toString()
val recName:String = intent.getStringExtra("userName").toString()
binding.userName.text = recName
chat = arrayListOf()
messageAdapter = MessageAdapter(chat)
binding.recyclerView.setHasFixedSize(true)
binding.recyclerView.layoutManager = LinearLayoutManager(this)
when {
userID < recID ->
{
roomID = userID + recID
}
userID.compareTo(recID) == 0 ->
{
Toast.makeText(this, "Error you are chatting with yourself!!!", Toast.LENGTH_SHORT).show()
}
else -> {
roomID = recID + userID
}
}
readMessages(userID,recID)
binding.btnSend.setOnClickListener {
val message: String = binding.textSend.text.toString()
if(message.isNotEmpty()){
sendMessage(userID,recID,message)
binding.textSend.text.clear()
}
else{
Toast.makeText(this,"You can't send empty message", Toast.LENGTH_SHORT).show()
}
}
binding.gps.setOnClickListener {
val uri = "http://maps.google.com/maps?daddr="
val intent = Intent(Intent.ACTION_VIEW, Uri.parse(uri))
intent.setPackage("com.google.android.apps.maps")
startActivity(intent)
}
}
private fun sendMessage(sender: String, rec: String, message: String){
val db = Firebase.firestore
val time: FieldValue = FieldValue.serverTimestamp()
val msg = hashMapOf(
"userID" to sender,
"recID" to rec,
"message" to message,
"time" to time,
"roomID" to roomID,
"isSeen" to false
)
db.collection("chats").document(roomID).collection("messages").document().set(msg,SetOptions.merge())
}
private fun readMessages(userId: String, recId: String){
val rootRef = Firebase.firestore
rootRef.collection("chats").document(roomID).collection("messages").orderBy("time", Query.Direction.ASCENDING).addSnapshotListener(object : EventListener<QuerySnapshot?>
{
override fun onEvent(#Nullable documentSnapshots: QuerySnapshot?, #Nullable e: FirebaseFirestoreException?)
{
if (e != null)
{
Log.e(TAG, "onEvent: Listen failed.", e)
return
}
chat.clear()
if (documentSnapshots != null)
{
for (queryDocumentSnapshots in documentSnapshots)
{
val msg = queryDocumentSnapshots.toObject(Message::class.java)
if (msg.recID == recId && msg.userID == userId || msg.recID == userId && msg.userID == recId)
{
chat.add(msg)
}
if(msg.recID.equals(userID).and(msg.userID.equals(recID))){
rootRef.collection("chats").document(roomID).collection("messages").document().update("isSeen",true)
}
messageAdapter = MessageAdapter(chat)
binding.recyclerView.adapter = messageAdapter
}
}
}
})
}
}
Adapter Class
class MessageAdapter(private val MessageList:ArrayList<Message>):RecyclerView.Adapter<MessageAdapter.MessageViewHolder>() {
private val left = 0
private val right = 1
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): MessageViewHolder {
return if(viewType==right){
val view1 = LayoutInflater.from(parent.context).inflate(R.layout.chat_sender_item,parent,false)
MessageViewHolder(view1)
}else{
val view2 = LayoutInflater.from(parent.context).inflate(R.layout.chat_receiver_item,parent,false)
MessageViewHolder(view2)
}
}
override fun onBindViewHolder(holder: MessageViewHolder, position: Int) {
val message:Message = MessageList[position]
holder.showMessage.text = message.message
if(position==MessageList.size-1){
if(message.isSeen)
{
holder.textSeen.text = "Seen"
}else{
holder.textSeen.text = "Delivered"
}
}else{
holder.textSeen.visibility = View.GONE
}
}
override fun getItemCount(): Int {
return MessageList.size
}
class MessageViewHolder(itemView:View) : RecyclerView.ViewHolder(itemView){
val showMessage: TextView = itemView.findViewById(R.id.showMessage)
val textSeen: TextView = itemView.findViewById(R.id.textSeen)
}
override fun getItemViewType(position: Int): Int {
val userID = FirebaseAuth.getInstance().currentUser!!.uid
return if(MessageList[position].userID==userID)
{
right
}else
{
left
}
}
}
Model Class
package com.aarondcosta99.foodreuseapp.model
data class Message(var userID:String? = "",var message:String? = "",var recID:String? = "",var isSeen:Boolean=false)
Firestore
This won't work:
rootRef.collection("chats").document(roomID).collection("messages").document().update("isSeen",true)
The document() call without any arguments creates a reference to a new non-existing document, which you then try to update. But update() only works when a document already exists, you can't use update() to create a document, so this code ends up doing nothing.
To update a document, you need to specify the complete path to that document. The fact that you need to update a lot of documents makes no difference to that fact, it just means you'll need to paths to a lot of documents.
As far as I can tell, you are trying to update the document that you read in documentSnapshots, which means you already have the DocumentReference handy and can update it with:
queryDocumentSnapshots.reference.update("isSeen",true)

Can't get received messages

Somehow I see in the app messages I sent, but can't see those which should be received from others. Also when I'm sending a message it's sent to all users. Here I'm sending two classes, adapter and main chat activity. I tried using inner classes, different types of getItemViewType functions but nothing works.
MessageAdapter
class MessageAdapter(val context: Context, val messageList: ArrayList<Message>):
RecyclerView.Adapter<RecyclerView.ViewHolder>() {
val ITEM_RECIEVE = 1
val ITEM_SENT = 2
class SentViewHolder(itemView: View) : RecyclerView.ViewHolder(itemView)
{
val sentMessage = itemView.findViewById<TextView>(R.id.txt_sent_message)
}
class RecieveViewHolder(itemView: View) : RecyclerView.ViewHolder(itemView)
{
val recieveMessage = itemView.findViewById<TextView>(R.id.txt_recieve_message)
}
override fun getItemViewType(position: Int): Int {
val currentMessage = messageList[position]
if (FirebaseAuth.getInstance().currentUser?.uid.equals(currentMessage.senderId)) {
return ITEM_SENT
}
else {
return ITEM_RECIEVE
}
}
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): RecyclerView.ViewHolder {
if (viewType == 1)
{
val view = LayoutInflater.from(context).inflate(R.layout.recieve, parent, false)
Log.d("tag2", "testrecieveviewholderview11")
return RecieveViewHolder(view)
}
else
{
val view = LayoutInflater.from(context).inflate(R.layout.sent, parent, false)
Log.d("tag", "testsentviewholderview22")
return SentViewHolder(view)
}
}
override fun onBindViewHolder(holder: RecyclerView.ViewHolder, position: Int) {
val currentMessage = messageList[position]
if(holder.javaClass == SentViewHolder::class.java)
{
val viewHolder = holder as SentViewHolder
holder.sentMessage.text = currentMessage.message
}
else
{
val viewHolder = holder as RecieveViewHolder
holder.recieveMessage.text = currentMessage.message
}
}
override fun getItemCount(): Int {
return messageList.size
}
}
And ChatActivity
var firebaseUser: FirebaseUser? = null
private lateinit var messageRecyclerView: RecyclerView
private lateinit var messageBox: EditText
private lateinit var sendButton: ImageButton
private lateinit var messageAdapter: MessageAdapter
private lateinit var messageList: ArrayList<Message>
private lateinit var mRef: DatabaseReference
var recieverRoom: String? = null
var senderRoom: String? = null
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_chat)
val intent = Intent()
val name = intent.getStringExtra("name")
val recieverUid = intent.getStringExtra("uid")
val senderUid = FirebaseAuth.getInstance().currentUser?.uid
mRef = FirebaseDatabase.getInstance().reference
senderRoom = recieverUid + senderUid
recieverRoom = senderUid + recieverUid
messageRecyclerView = findViewById(R.id.RecyclerViewChat)
messageBox = findViewById(R.id.messageBox)
sendButton = findViewById(R.id.sendButton)
messageList = ArrayList()
messageAdapter = MessageAdapter(this, messageList)
messageRecyclerView.layoutManager = LinearLayoutManager(this)
messageRecyclerView.scrollToPosition(messageAdapter.itemCount-1)
messageRecyclerView.adapter = messageAdapter
mRef.child("chats").child(senderRoom!!).child("messages")
.addValueEventListener(object : ValueEventListener{
override fun onDataChange(snapshot: DataSnapshot) {
messageList.clear()
for (postSnapshot in snapshot.children)
{
val message = postSnapshot.getValue(Message::class.java)
messageList.add(message!!)
}
messageAdapter.notifyDataSetChanged()
}
override fun onCancelled(error: DatabaseError) {
}
})
sendButton.setOnClickListener {
if (messageBox.text.toString().isEmpty() || messageBox.text.toString().isBlank())
{
messageBox.setText("")
}
else {
val message = messageBox.text.toString()
val messageObject = Message(message, senderUid)
mRef.child("chats").child(senderRoom!!).child("messages").push()
.setValue(messageObject).addOnSuccessListener {
mRef.child("chats").child(recieverRoom!!).child("messages").push()
.setValue(messageObject)
}
messageBox.setText("")
}
}
}
}
The error coming in this code is "Unresolved reference: message" and "Unresolved reference: senderId" in MessageAdapter. MessageAdapter is not able to take variables that are declared in Message class(message and senderId).

Can we retrieve firebase data into spinner?

I have added firebase database and the data also gets saved into the firebase realtime database, but it doesnot gets shown into the spinner, my spinner is showing no value.If theres some other way?
This is the code of my fragment:
class IncomeFragment: Fragment(){
//FAB
lateinit var addBankFab: FloatingActionButton
lateinit var addBankText: TextView
//Spinner
lateinit var spinner: Spinner
lateinit var dropDown: TextView
//Firebase Database
lateinit var mAuth: FirebaseAuth
lateinit var mIncomeDatabase: DatabaseReference
lateinit var mBankDatabase: DatabaseReference
lateinit var helper: FirebaseHelper
//Recycler View
lateinit var recyclerView: RecyclerView
//TextView
lateinit var incomeTotal : TextView
//Update Edit Text
lateinit var editAmount: EditText
lateinit var editType: EditText
lateinit var editNote: EditText
lateinit var editBankName:EditText
//Button for update and delete
lateinit var btnUpdate: Button
lateinit var btnDelete: Button
lateinit var btnSave : Button
lateinit var btnCancel:Button
//Data item Value
lateinit var type: String
lateinit var note: String
var amount: Int = 0
lateinit var post_key:String
lateinit var name:String
lateinit var ac:String
override fun onCreateView(
inflater: LayoutInflater, container: ViewGroup?,
savedInstanceState: Bundle?
): View? {
// Inflate the layout for this fragment
val myview= inflater.inflate(R.layout.fragment_income, container, false)
mAuth= FirebaseAuth.getInstance()
val mUser = mAuth.currentUser
val uid = mUser?.uid
addBankFab=myview.findViewById(R.id.add_bank_fab)
addBankText=myview.findViewById(R.id.add_bank_text)
spinner=myview.findViewById(R.id.incomeSpinner)
mIncomeDatabase =
FirebaseDatabase.getInstance().reference.child("IncomeData").child(uid.toString())
incomeTotal=myview.findViewById(R.id.income_txt_result)
mBankDatabase= FirebaseDatabase.getInstance().reference.child("BankData").child(uid.toString())
helper = FirebaseHelper(mBankDatabase)
spinner.setAdapter(
activity?.let {
ArrayAdapter<String>(
it,
android.R.layout.simple_list_item_1,
helper.retrieve()
)
}
)
recyclerView=myview.findViewById(R.id.incomeRecyclerView)
val layoutManager = LinearLayoutManager(activity)
layoutManager.reverseLayout = true
layoutManager.stackFromEnd = true
recyclerView.setHasFixedSize(true)
recyclerView.layoutManager = layoutManager
mIncomeDatabase.addValueEventListener(object : ValueEventListener {
override fun onDataChange(dataSnapshot: DataSnapshot) {
var totalvalue :Int = 0
for (ds in dataSnapshot.children) {
val data: Data = ds.getValue<Data>(Data::class.java)!!
totalvalue+=data.amount
val stTotalValue:String = valueOf(totalvalue)
incomeTotal.text = stTotalValue+".00"
}
}
override fun onCancelled(databaseError: DatabaseError) {}
})
return myview
}
private fun insertBank() {
val bankdialog = AlertDialog.Builder(activity)
val inflater = LayoutInflater.from(activity)
val view: View = inflater.inflate(R.layout.add_bank_layout, null)
bankdialog.setView(view)
val dialog = bankdialog.create()
dialog.setCancelable(false)
val BankName = view.findViewById<EditText>(R.id.account_bank)
val BankAc = view.findViewById<EditText>(R.id.account_number)
val btnSaveBank = view.findViewById<Button>(R.id.btn_save_bank)
val btnCancelBank = view.findViewById<Button>(R.id.btn_cancel_bank)
btnSaveBank.setOnClickListener {
val name = BankName.text.toString().trim()
val ac = BankAc.text.toString().trim()
if (TextUtils.isEmpty(name)) {
BankName.error = "Required Field..."
return#setOnClickListener
}
if (TextUtils.isEmpty(ac)) {
BankAc.error = "Required Field..."
return#setOnClickListener
}
val bankacno = ac.toInt()
val id: String? = mBankDatabase.push().key
val mDate: String = DateFormat.getDateInstance().format(Date())
val bankdata = EmiData(bankacno, name, id, mDate)
mBankDatabase.child(id.toString()).setValue(bankdata)
Toast.makeText(activity, "DATA ADDED", Toast.LENGTH_SHORT).show()
dialog.dismiss()
}
btnCancelBank.setOnClickListener {
dialog.dismiss()
}
dialog.show()
}
override
fun onStart() {
super.onStart()
val options = FirebaseRecyclerOptions.Builder<Data>()
.setQuery(mIncomeDatabase, Data::class.java)
.setLifecycleOwner(this)
.build()
val firebaseRecyclerAdapter: FirebaseRecyclerAdapter<Data, MyViewHolder> =
object : FirebaseRecyclerAdapter<Data, MyViewHolder>(options) {
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): MyViewHolder {
return MyViewHolder(
LayoutInflater.from(parent.context)
.inflate(R.layout.income_recycler_data, parent, false)
)
}
override fun onBindViewHolder(holder: MyViewHolder, position: Int, model: Data) {
holder.setType(model.type)
holder.setAmount(model.amount)
holder.setDate(model.date)
holder.setNote(model.note)
holder.mView.setOnClickListener {
post_key= getRef(position).key.toString()
type=model.type
note=model.note
amount=model.amount
updateDataItem()
}
}
}
recyclerView.adapter = firebaseRecyclerAdapter
}
class MyViewHolder(itemView: View) : ViewHolder(itemView) {
val mView = itemView
fun setType(type: String) {
val mType = mView.findViewById<TextView>(R.id.type_txt_income)
mType.text = type
}
fun setNote(note: String) {
val mNote = mView.findViewById<TextView>(R.id.note_txt_income)
mNote.text = note
}
fun setDate(date: String) {
val mDate = mView.findViewById<TextView>(R.id.date_txt_income)
mDate.text = date
}
fun setAmount(amount: Int) {
val mAmount = mView.findViewById<TextView>(R.id.amount_txt_income)
val stAmount = valueOf(amount)
mAmount.text = stAmount
}
}
private fun updateDataItem() {
val mydialog = AlertDialog.Builder(activity)
val inflater = LayoutInflater.from(activity)
val myView: View = inflater.inflate(R.layout.update_data_item, null)
mydialog.setView(myView)
val dialog = mydialog.create()
val editAmount = myView.findViewById<EditText>(R.id.amount_edit)
val editType = myView.findViewById<EditText>(R.id.type_edit)
val editNote = myView.findViewById<EditText>(R.id.note_edit)
//Set data to edit text..
editType.setText(type)
editType.setSelection(type.length)
editNote.setText(note)
editNote.setSelection(note.length)
editAmount.setText(valueOf(amount))
editAmount.setSelection(valueOf(amount).length)
val btnUpdate = myView.findViewById<Button>(R.id.btn_update)
val btnDelete = myView.findViewById<Button>(R.id.btn_delete)
btnUpdate.setOnClickListener {
type = editType.text.toString().trim()
note = editNote.text.toString().trim()
var mdAmount = amount.toString()
mdAmount = editAmount.text.toString().trim { it <= ' ' }
val myAmount = mdAmount.toInt()
val mDate: String = DateFormat.getDateInstance().format(Date())
val data = Data(myAmount, type, note, post_key, mDate)
mIncomeDatabase.child(post_key).setValue(data)
dialog.dismiss()
}
btnDelete.setOnClickListener {
mIncomeDatabase.child(post_key).removeValue()
dialog.dismiss()
}
dialog.show()
}
}
This is my firebase helper:
class FirebaseHelper(val db: DatabaseReference) {
private var saved: Boolean? = null
//SAVE
fun save(bankData: BankData?): Boolean? {
saved = if (bankData == null) {
false
} else {
try {
db.child("name").push().setValue(bankData)
true
} catch (e: DatabaseException) {
e.printStackTrace()
false
}
}
return saved
}
//READ
fun retrieve(): ArrayList<String> {
val bankNames = ArrayList<String>()
db.addChildEventListener(object : ChildEventListener {
override fun onChildAdded(
dataSnapshot: DataSnapshot,
s: String?
) {
fetchData(dataSnapshot, bankNames)
}
override fun onChildChanged(
dataSnapshot: DataSnapshot,
s: String?
) {
fetchData(dataSnapshot, bankNames)
}
override fun onChildRemoved(dataSnapshot: DataSnapshot) {}
override fun onChildMoved(
dataSnapshot: DataSnapshot,
s: String?
) {
}
override fun onCancelled(databaseError: DatabaseError) {}
})
return bankNames
}
private fun fetchData(
snapshot: DataSnapshot,
bankData: ArrayList<String>
) {
bankData.clear()
val name: BankData? = snapshot.getValue(BankData::class.java)
bankData.add(bankData.toString())
}
}
Your spinner shows no value because the data is not retrieved yet from the DB.
So what you should do is create a callback from FirebaseHelper to IncomeFragment
First, create a callback
interface FirebaseHelperCallback {
fun dataRetrievedFromDB(data: List<String>)
}
Second, create a variable, setter function and call dataRetrievedFromDB function in FirebaseHelper class
class FirebaseHelper(val db: DatabaseReference) {
private lateinit var firebaseHelperCallback: FirebaseHelperCallback
fun setFirebaseHelperCallback(firebaseHelperCallback: FirebaseHelperCallback) {
this.firebaseHelperCallback = firebaseHelperCallback
}
...
private fun fetchData(snapshot: DataSnapshot, bankData: ArrayList<String>) {
bankData.clear()
val name: BankData? = snapshot.getValue(BankData::class.java)
bankData.add(bankData.toString())
firebaseHelperCallback.dataRetrievedFromDB(bankData)
}
}
Lastly, implement the callback in IncomeFragment
class IncomeFragment: Fragment(), FirebaseHelperCallback {
override fun onCreateView(
inflater: LayoutInflater, container: ViewGroup?,
savedInstanceState: Bundle?
): View? {
...
helper.setFirebaseHelperCallback(this)
}
...
override fun dataRetrievedFromDB(data: List<String>) {
spinner.setAdapter(
activity?.let {
ArrayAdapter<String>(
it,
android.R.layout.simple_list_item_1,
data
)
}
)
}
}

Listview duplicating itself whenever any event occurs in activity

I have backend firebase which i am using to populate the listview , i was implementing the search functionality suddenly i found a weird behavior in listview ,it is creating duplicates in numbers like 30-40 and above.
Please help me i was batteling for it from 3 days. i am very new to development so any suggestions to code optimizing will also be taken as help!
class Menu : AppCompatActivity(){
private var prevKey : String? = null
var listAdapter : CustomAdapter ? = null
private val listItemArrayList = ArrayList<ListItem>()
var rootRef : FirebaseDatabase? = null
var adminRef : DatabaseReference? = null
var mAuth : FirebaseAuth? = null
var helper : CustomAdapter?=null
private var user : String?=null
var mAuthListener: FirebaseAuth.AuthStateListener? = null
var Items = ArrayList<String>()
var isSectionBoolean = ArrayList<Boolean>()
var ItemCategory= ArrayList<String>()
var ItemCost = ArrayList<Int>()
var listView : ListView? = null
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_menu)
mAuth = FirebaseAuth.getInstance()
mAuthListener = FirebaseAuth.AuthStateListener { }
rootRef = FirebaseDatabase.getInstance()
user =mAuth!!.currentUser!!.phoneNumber as String
adminRef = rootRef!!.getReference("AdminCafe").child(user!!)
listView = findViewById(R.id.admindynamiclist)
listAdapter = CustomAdapter(listItemArrayList,this)
listView!!.adapter = listAdapter
listView!!.isTextFilterEnabled = true
SearchView.setOnQueryTextListener(object : SearchView.OnQueryTextListener{
override fun onQueryTextSubmit(query: String?): Boolean {
return false
}
override fun onQueryTextChange(newText: String?): Boolean {
listAdapter!!.filter(newText.toString())
return false
}
})
getData()
}
fun addAct(v:View)
{
val intent = Intent(applicationContext,AddActivity::class.java)
startActivity(intent)
}
private fun getData() {
println("getData")
var menucatRef = adminRef!!.child("MenuItem")
menucatRef.addValueEventListener(object : ValueEventListener{
override fun onCancelled(p0: DatabaseError) {
}
override fun onDataChange(p0: DataSnapshot) {
for(Snap in p0.children)
{
println("wtfff")
println("Child"+Snap.childrenCount)
getDataFromKey(Snap.key.toString(),Snap.childrenCount.toInt())
}
}
})
}
private fun getDataFromKey(key: String, child :Int) {
listItemArrayList.clear()
println("called")
var count = 0
var counter = 0
var Category = CategoryHeader()
var menuRef = adminRef!!.child("MenuItem").child(key)
menuRef.addListenerForSingleValueEvent(object : ValueEventListener{
override fun onCancelled(p0: DatabaseError) {
}
override fun onDataChange(p0: DataSnapshot) {
var catKey = p0.key.toString()
for(snap in p0!!.children)
{
if(count == 0)
{
Category!!.setheader(catKey)
listItemArrayList!!.add(Category)
println("Seperator will be added")
}
else
{
var hashMap = snap.value as HashMap<String,String>
var itemName = snap.key
var isVeg = hashMap["isVeg"]
var itemCost = hashMap["itemCost"]!!.toInt()
var isSig = hashMap["isSig"]
var ItemHelper = Item()
if(itemName!=null)
{
ItemHelper.setItemName(itemName)
}
if(itemCost!=null)
{
ItemHelper.setItemCost(itemCost)
}
listItemArrayList!!.add(ItemHelper)
}
count++
}
listAdapter!!.notifyDataSetChanged()
}
})
}
interface ListItem {
fun isHeader(): Boolean
fun getName(): String
fun getItemCost() : Int
}
fun editAct(v:View)
{
println("Inside edit")
}
}
And Adapter class
class CustomAdapter(private var listItem : ArrayList<Menu.ListItem>, private val context: Activity) : BaseAdapter() {
var orig = ArrayList<Menu.ListItem> ()
override fun getView(position: Int, convertView: View?, parent: ViewGroup?): View {
orig.addAll(listItem)
println("List Item is"+listItem)
println("List Item is"+orig)
var holder = ViewHolder()
var customView = convertView
var flag = true
if (convertView == null) {
val layoutInflater = context.layoutInflater
if(listItem.get(position).isHeader()) {
println("position"+position)
customView = layoutInflater.inflate(R.layout.seperator, null)
holder.tvLabel = customView.categoryText
} else {
println("position"+position)
customView = layoutInflater.inflate(R.layout.list_item, null)
holder.tvLabel = customView.itemad
holder.itemCost = customView.cost
flag = false
}
customView.setTag(holder)
}
else
{
customView = convertView
holder = convertView!!.tag as ViewHolder
}
if(flag) {
println("Custoom Flag is"+flag)
holder!!.tvLabel!!.text = listItem.get(position).getName()
}
else {
println("Custoom Flag is"+flag)
holder!!.tvLabel!!.text = listItem.get(position).getName()
holder.itemCost!!.text = listItem.get(position).getItemCost().toString()
}
return customView!!
}
override fun getItem(position: Int): Any {
return listItem.get(position)
}
override fun getItemId(position: Int): Long {
return position.toLong()
}
override fun getCount(): Int {
return listItem.size
}
private inner class ViewHolder {
var tvLabel: TextView? = null
var itemCost: TextView? = null
}
fun filter(query : String)
{
println("called")
listItem.clear()
var search = query
search = search.toLowerCase(Locale.getDefault())
if(search.isEmpty())
{
listItem.addAll(orig!!)
println("Inside size 0")
}
else
{
var counter = 0
for(result in orig!! )
{
if(result.getName().toLowerCase().contains(search))
{
println("Result is "+result.getName())
println("listItem"+listItem)
}
}
}
}
}

Categories

Resources