UPDATED QUESTION
I have an ordered List of Chats (userMsglist), but since I need to show the User Profile Image and Name associated with each chat, I have to create a mUsers list based on the Users node in the FB Realtime DB. At this point, I loose the order present. How do I create a mUsers list based on the order in userMsgList
private fun retrieveMessageList()
{
mUsers = ArrayList()
val ref = FirebaseDatabase.getInstance().reference.child("Users")
ref.addValueEventListener(object : ValueEventListener {
override fun onDataChange(p0: DataSnapshot) {
(mUsers as ArrayList).clear()
// usersMsgList?.sortedBy { it.getChattimeStmp() }
//Sorting of chatlist
Collections.sort(usersMsgList!!, this#Messages::compare)
for (dataSnapshot in p0.children) {
val user = dataSnapshot.getValue(Users::class.java)
for (eachMessageList in usersMsgList!!) {
if(eachMessageList.getId().equals(user!!.getUID()) && !firebaseUser?.uid.equals(eachMessageList.getId())) {
(mUsers as ArrayList).add(user)
}
}
}
userMsgAdapter = UserMsgAdapter(context!!, (mUsers as ArrayList<Users>), true)
recycler_view_msgList.adapter = userMsgAdapter
}
override fun onCancelled(p0: DatabaseError) {
}
}
)
}
private fun compare(o1: MessageList, o2: MessageList): Int {
return if (o1.getChattimeStmp()!! < o2.getChattimeStmp()!!) 1 else if (o1.getChattimeStmp() == o2.getChattimeStmp()) 0 else -1
}
The image of for the structure of Chatlist is as below:
The image for the structure of the User is below:
The full code is below
class Messages : Fragment() {
private var userMsgAdapter: UserMsgAdapter? = null
private var mUsers: List<Users>? = null
private var usersMsgList: List<MessageList>? = null
private var firebaseUser : FirebaseUser? = null
lateinit var recycler_view_msgList : RecyclerView
override fun onCreateView(
inflater: LayoutInflater, container: ViewGroup?,
savedInstanceState: Bundle?
): View? {
// Inflate the layout for this fragment
val view = inflater.inflate(R.layout.fragment_messages, container, false)
recycler_view_msgList = view.findViewById(R.id.recycler_view_msglist)
recycler_view_msgList.setHasFixedSize(true)
recycler_view_msgList.layoutManager = LinearLayoutManager(context)
firebaseUser = FirebaseAuth.getInstance().currentUser
usersMsgList = ArrayList()
val ref = FirebaseDatabase.getInstance().reference.child("ChatList").child((firebaseUser!!.uid))
ref.addValueEventListener(object : ValueEventListener {
override fun onDataChange(p0: DataSnapshot) {
(usersMsgList as ArrayList).clear()
for (dataSnapshot in p0.children) {
val messageList = dataSnapshot.getValue(MessageList::class.java)
(usersMsgList as ArrayList).add(messageList!!)
}
retrieveMessageList()
}
override fun onCancelled(p0: DatabaseError) {
}
})
updateToken(FirebaseInstanceId.getInstance().token)
return view
}
private fun updateToken(token: String?)
{
val ref = FirebaseDatabase.getInstance().reference.child("Tokens")
val Token1 = Token(token!!)
ref.child(firebaseUser!!.uid).setValue(Token1)
}
private fun retrieveMessageList()
{
mUsers = ArrayList()
val ref = FirebaseDatabase.getInstance().reference.child("Users")
ref.addValueEventListener(object : ValueEventListener {
override fun onDataChange(p0: DataSnapshot) {
(mUsers as ArrayList).clear()
// usersMsgList?.sortedBy { it.getChattimeStmp() }
//Sorting of chatlist
Collections.sort(usersMsgList!!, this#Messages::compare)
for (dataSnapshot in p0.children) {
val user = dataSnapshot.getValue(Users::class.java)
for (eachMessageList in usersMsgList!!) {
if(eachMessageList.getId().equals(user!!.getUID()) && !firebaseUser?.uid.equals(eachMessageList.getId())) {
(mUsers as ArrayList).add(user)
}
}
}
userMsgAdapter = UserMsgAdapter(context!!, (mUsers as ArrayList<Users>), true)
recycler_view_msgList.adapter = userMsgAdapter
}
override fun onCancelled(p0: DatabaseError) {
}
}
)
}
private fun compare(o1: MessageList, o2: MessageList): Int {
return if (o1.getChattimeStmp()!! < o2.getChattimeStmp()!!) 1 else if (o1.getChattimeStmp() == o2.getChattimeStmp()) 0 else -1
}
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
messages_fab.setOnClickListener{
val intent = Intent(context, MyContacts::class.java)
startActivity(intent)
}
}
}
Related
EDIT
i changed my code and got a result but it breaks the data into separate values. it reads all the data from the database for each child. i have 2 childs but it only retrieves the last childs data and display its values separately. it stores its value from the variable eta_text
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState)
clear_all = view.findViewById(R.id.clear_all)
notificationView = view.findViewById(R.id.notificationList)
notificationArray = arrayListOf()
getNotifData()
var linearLayoutManager = LinearLayoutManager(context)
notificationView.layoutManager = linearLayoutManager
notificationView.setHasFixedSize(true)
}
private fun getNotifData() {
val user = FirebaseAuth.getInstance().currentUser
val useremail = user!!.email
dbref = FirebaseDatabase.getInstance().reference
dbref.child("Students").orderByChild("email").equalTo(useremail.toString()).addValueEventListener(object : ValueEventListener{
override fun onDataChange(snapshot: DataSnapshot) {
for (ds in snapshot.children) {
val idNumber: String? = ds.key
dbref.child("Notification").child(idNumber.toString()).addValueEventListener(object : ValueEventListener{
override fun onDataChange(dsnapshot: DataSnapshot) {
for (dsd in dsnapshot.children) {
val key: String? = dsd.key
dbref.child("Notification").child(idNumber.toString()).child(key.toString()).addValueEventListener(object : ValueEventListener{
override fun onDataChange(dsnap: DataSnapshot) {
notificationArray.clear()
if (dsnap.exists()){
for (queueSnapshot in dsnap.children){
notificationArray.add(Notification(queueSnapshot.value.toString()))
}
notifadapter = MyAdapter_Notification(notificationArray)
notificationView.adapter = notifadapter
}
}
override fun onCancelled(error: DatabaseError) {
TODO("Not yet implemented")
}
})
}
}
override fun onCancelled(error: DatabaseError) {
TODO("Not yet implemented")
}
})
}
}
override fun onCancelled(error: DatabaseError) {
TODO("Not yet implemented")
}
})
}
My data class
package com.example.sqms
data class Notification(var eta_text : String ?= null,
var office_name : String ?= null,
var time_text : String ?= null)
My Adapter
class MyAdapter_Notification (private val notificationList : ArrayList<Notification>)
: RecyclerView.Adapter<MyAdapter_Notification.MyViewHolder>() {
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): MyViewHolder {
val notificationView = LayoutInflater.from(parent.context).inflate(R.layout.notification_view,parent,false)
return MyViewHolder(notificationView)
}
override fun onBindViewHolder(holder: MyViewHolder, position: Int) {
val currentItem = notificationList[position]
holder.eta_text.text = currentItem.eta_text
holder.office_name.text = currentItem.office_name
holder.time_text.text = currentItem.time_text
}
override fun getItemCount(): Int {
return notificationList.size
}
inner class MyViewHolder(notificationView : View) : RecyclerView.ViewHolder(notificationView){
val eta_text : TextView = itemView.findViewById(R.id.eta_text)
val office_name : TextView = itemView.findViewById(R.id.office_name)
val time_text : TextView = itemView.findViewById(R.id.time_text)
}
}
picture below is the values from database
database
picture below is the data that is displayed separately
notification recycler view
i just solved it. i just removed the 3rd nested databasereference and changed the data writing
private fun getNotifData() {
val user = FirebaseAuth.getInstance().currentUser
val useremail = user!!.email
dbref = FirebaseDatabase.getInstance().reference
dbref.child("Students").orderByChild("email").equalTo(useremail.toString()).addValueEventListener(object : ValueEventListener{
override fun onDataChange(snapshot: DataSnapshot) {
for (ds in snapshot.children) {
val idNumber: String? = ds.key
dbref.child("Notification").child(idNumber.toString()).addValueEventListener(object : ValueEventListener{
override fun onDataChange(dsnapshot: DataSnapshot) {
notificationArray.clear()
if (dsnapshot.exists()){
for (queueSnapshot in dsnapshot.children){
val notif = queueSnapshot.getValue(Notification::class.java)
if (notif != null) {
notificationArray.add(notif)
}
}
notifadapter = MyAdapter_Notification(notificationArray)
notificationView.adapter = notifadapter
}
if (notifadapter.itemCount==0) {
notificationView.visibility = View.GONE;
new_notif.visibility = View.VISIBLE;
}
else {
notificationView.visibility = View.VISIBLE;
new_notif.visibility = View.GONE;
}
}
override fun onCancelled(error: DatabaseError) {
TODO("Not yet implemented")
}
})
}
}
override fun onCancelled(error: DatabaseError) {
TODO("Not yet implemented")
}
})
}
I tried to add a new data to firebase and then show it in a recyclerview, but after i add the data the recyclerview just loop the whole data until the data is done uploading thus creating a view like this :
the looped recyclerview
As you can see in the picture that in that link, i tried to add "food 6" data but as the result for the adding process the recyclerview keep updating the items inside it until the adding process complete
Here is my adapter code
class FoodAdapter (private var dataList : ArrayList<Food>): RecyclerView.Adapter<FoodAdapter.MyViewholder>() {
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): MyViewholder {
val itemView = LayoutInflater.from(parent.context).inflate(R.layout.food_recyclerview,parent,false)
return MyViewholder(itemView)
}
override fun onBindViewHolder(holder: MyViewholder, position: Int) {
val currentItem = dataList[position]
Log.w("adapater",currentItem.image_pic.toString())
Picasso.get().load(currentItem.image_pic).into(holder.foodPic)
holder.food_name.text = currentItem.name
holder.food_price.text = currentItem.price.toString()
if (currentItem.avail == true){
holder.food_avail.text = "Tersedia"
holder.food_avail.setTextColor(Color.GREEN)
} else {
if (currentItem.avail == false){
holder.food_avail.text = "Habis"
holder.food_avail.setTextColor(Color.RED)
} else {
holder.food_avail.text = "Error"
}
}
}
override fun getItemCount(): Int {
return dataList.size
}
inner class MyViewholder (itemView : View): RecyclerView.ViewHolder(itemView){
val foodPic : ImageView = itemView.findViewById(R.id.iv_gambar_makanan)
val food_name : TextView = itemView.findViewById(R.id.tv_nama_makanan)
val food_avail : TextView = itemView.findViewById(R.id.tv_status_makanan)
val food_price : TextView = itemView.findViewById(R.id.tv_harga_makanan)
}
}
here is my update data to firebase code
private fun addDatatoFirebase() {
val dataRef = ref.child(preferences.getValue("username").toString()).child("FoodList/"+ UUID.randomUUID().toString())
var PicUrl = ""
val addImage = StorageRef.child(preferences.getValue("username").toString())
.child("food_pics/" + UUID.randomUUID())
Log.i("Cycle", "Add Image to Firebase")
addImage.putFile(FilePath).addOnSuccessListener {
addImage.downloadUrl.addOnSuccessListener {
PicUrl = it.toString()
dataRef.child("image_pic").setValue(PicUrl)
}
}
Log.i("URL",addImage.toString())
dataRef.addValueEventListener(object : ValueEventListener{
override fun onDataChange(snapshot: DataSnapshot) {
id = snapshot.ref
Log.w("PicUrl data",PicUrl)
dataRef.child("name").setValue(food_name)
dataRef.child("avail").setValue(availability)
dataRef.child("price").setValue(food_price.toInt())
}
override fun onCancelled(error: DatabaseError) {
Toast.makeText(applicationContext,"Error",Toast.LENGTH_SHORT)
}
})
}
and here is the code to get the data
private fun getFoodData() {
val foodData = ref.child(preferences.getValue("username").toString()).child("FoodList")
foodData.addValueEventListener(object : ValueEventListener{
override fun onDataChange(snapshot: DataSnapshot) {
if (snapshot != null) {
for (userSnapshot in snapshot.children) {
var data = userSnapshot.getValue(Food::class.java)
foodDataArrayList.add(data!!)
}
}
foodList.adapter = FoodAdapter(foodDataArrayList)
}
override fun onCancelled(error: DatabaseError) {
Toast.makeText(applicationContext,"Error",Toast.LENGTH_SHORT)
}
})
foodList.adapter = FoodAdapter(foodDataArrayList)
}
Can anyone show me how to fix this issue?
You missed out on one thing. Whenever data gets changed, you get all the entries again and again without removing the previous un-updated data. So, the simple solution would be to clear the list before getting the data. Try this code:
private fun getFoodData() {
val foodData = ref.child(preferences.getValue("username").toString()).child("FoodList")
foodData.addValueEventListener(object : ValueEventListener{
override fun onDataChange(snapshot: DataSnapshot) {
if (snapshot != null) {
foodDataArrayList.clear() // added this line
for (userSnapshot in snapshot.children) {
var data = userSnapshot.getValue(Food::class.java)
foodDataArrayList.add(data!!)
}
}
foodList.adapter = FoodAdapter(foodDataArrayList)
}
override fun onCancelled(error: DatabaseError) {
Toast.makeText(applicationContext,"Error",Toast.LENGTH_SHORT)
}
})
}
I am building a chatting app using firebase realtime database.
I am storing the messages in both accounts simultaneously.
This is my fragment to send message:
class DmFragment : Fragment() {
lateinit var binding: FragmentDMBinding
lateinit var user: User
val list = ArrayList<Message>()
lateinit var auth: FirebaseAuth
lateinit var firebaseDatabase: FirebaseDatabase
lateinit var reference: DatabaseReference
lateinit var usersDMAdapter: UsersDMAdapter
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
arguments?.let {
user = it.getSerializable("user") as User
}
}
override fun onCreateView(
inflater: LayoutInflater, container: ViewGroup?,
savedInstanceState: Bundle?
): View? {
binding = FragmentDMBinding.inflate(LayoutInflater.from(requireContext()), container, false)
auth = FirebaseAuth.getInstance()
val currentUser = auth.currentUser!!
firebaseDatabase = FirebaseDatabase.getInstance()
reference = firebaseDatabase.getReference("users")
binding.apply {
sendBtn.setOnClickListener {
val smsText = message.text.toString()
val simpleDateFormat = SimpleDateFormat("dd.MM.yyyy HH.ss")
val date = simpleDateFormat.format(Date())
val message1 = Message(smsText, date, currentUser.uid, user.uid)
val key = reference.push().key
reference.child("${currentUser.uid}/messages/${user.uid!!}/$key")
.setValue(message1)
reference.child("${user.uid}/messages/${currentUser.uid}/$key")
.setValue(message1)
message.text.clear()
}
reference.child("${currentUser.uid}/messages/${user.uid}")
.addValueEventListener(object : ValueEventListener {
override fun onDataChange(snapshot: DataSnapshot) {
val children = snapshot.children
for (child in children) {
val value = child.getValue(Message::class.java)
if (value != null) {
list.add(value)
}
}
usersDMAdapter = UsersDMAdapter(list, currentUser.uid)
messageRv.adapter = usersDMAdapter
}
override fun onCancelled(error: DatabaseError) {
}
})
back.setOnClickListener {
findNavController().popBackStack()
}
userName.text = user.displayName
Picasso.get().load(user.photoUrl).into(userImage)
}
return binding.root
}
}
This is the adapter file that i used in the DMFragment:
class UsersDMAdapter(var list: List<Message>, var uid: String) :
RecyclerView.Adapter<RecyclerView.ViewHolder>() {
inner class FromVh(val fromBinding: ItemFromBinding) :
RecyclerView.ViewHolder(fromBinding.root) {
fun onBind(message: Message) {
fromBinding.apply {
messageTv.text = message.message
messageDateTv.text = message.date
}
}
}
inner class ToVh(val toBinding: ItemToBinding) :
RecyclerView.ViewHolder(toBinding.root) {
fun onBind(message: Message) {
toBinding.apply {
messageTv.text = message.message
messageDateTv.text = message.date
}
}
}
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): RecyclerView.ViewHolder {
if (viewType == 1) {
return FromVh(
ItemFromBinding.inflate(
LayoutInflater.from(parent.context),
parent,
false
)
)
} else {
return ToVh(
ItemToBinding.inflate(
LayoutInflater.from(parent.context),
parent,
false
)
)
}
}
override fun onBindViewHolder(holder: RecyclerView.ViewHolder, position: Int) {
if (getItemViewType(position)==1){
val fromVh = holder as FromVh
fromVh.onBind(list[position])
}else{
val toVh = holder as ToVh
toVh.onBind(list[position])
}
}
override fun getItemViewType(position: Int): Int {
return if (list[position].fromUid == uid) {
1
} else{
2
}
}
override fun getItemCount(): Int = list.size
}
This is my fragment that shows all users excluding myself:
class UserRecyclerFragment : Fragment() {
lateinit var binding: FragmentUserRecyclerBinding
lateinit var userRvAdapter: UserRvAdapter
var list = ArrayList<User>()
lateinit var auth: FirebaseAuth
lateinit var firebaseDatabase: FirebaseDatabase
lateinit var reference: DatabaseReference
override fun onCreateView(
inflater: LayoutInflater, container: ViewGroup?,
savedInstanceState: Bundle?
): View? {
binding = FragmentUserRecyclerBinding.inflate(
LayoutInflater.from(requireContext()),
container,
false
)
auth = FirebaseAuth.getInstance()
val currentUser = auth.currentUser!!
firebaseDatabase = FirebaseDatabase.getInstance()
reference = firebaseDatabase.getReference("users")
val email = currentUser.email
val displayName = currentUser.displayName
val photo = currentUser.photoUrl
val phoneNumber = currentUser.phoneNumber
val uid = currentUser.uid
val user = User(
email,
displayName,
photo.toString(),
phoneNumber,
uid
)
reference.addListenerForSingleValueEvent(object : ValueEventListener {
override fun onDataChange(snapshot: DataSnapshot) {
list.clear()
val filterList = arrayListOf<User>()
val children = snapshot.children
for (child in children) {
val value = child.getValue(User::class.java)
if (value != null && uid != value.uid) {
list.add(value)
}
if (value != null && value.uid == uid) {
filterList.add(value)
}
}
if (filterList.isEmpty()) {
reference.child(uid).setValue(user)
}
userRvAdapter = UserRvAdapter(list, object : UserRvAdapter.OnItemClickListener {
override fun onItemCick(user: User) {
val bundle = Bundle()
bundle.putSerializable("user", user)
findNavController().navigate(R.id.dmFragment, bundle)
}
})
binding.rv.adapter = userRvAdapter
}
override fun onCancelled(error: DatabaseError) {
}
})
return binding.root
}
}
Whenever i chat (send/receive) in DM, it is showing messages. But when I go back, messages that added in my user account is being deleted automatically. If i come back again, it is not showing the messages that have been saved in other person's account either. And i do not know what to do. Can anyone help?
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
)
}
)
}
}
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)
}
}
}
}
}