KOTLIN: My data do not gets from firebase realtime database - android

I am trying to get data from my firebase realtime database.
In my database there is a table whose name is "groups" and it has 3 values "datetime", "title", "username".
I want to get title value and add my list.
Normally in static version, I have a list which includes GroupModelRetrieve types and lists the titles in listview
Now I cant see the titles in listview It is empty
I am new in mobile programming. So, I appreaciate that if you help me.
Here is my code
val list: ArrayList<GroupModelRetrieve> = arrayListOf()
database = FirebaseDatabase.getInstance()
databaseReference = database?.getReference("groups")!!.child("title")
val postListener = object : ValueEventListener{
override fun onCancelled(error: DatabaseError) {
Toast.makeText(requireContext(), "Fail to get data.", Toast.LENGTH_SHORT).show();
}
override fun onDataChange(snapshot: DataSnapshot) {
val data = snapshot.getValue()
val item = GroupModelRetrieve(data.toString())
list.add(item)
}
}
databaseReference!!.addValueEventListener(postListener)
val adapter = GroupsAdapter(requireActivity(), list)
v.findViewById<ListView>(R.id.list_view_groups).adapter = adapter
Also I am adding my model
public class GroupModelRetrieve(Title: String) {
val title:String
init {
title = Title
}
}
If you want, I can add more codes. Thanks for your help.

You need to notify the list with the new changes, as by default Firebase works asynchronously to the main thread, so setting the adapter to the list will get called before any Firebase response.
val adapter = GroupsAdapter(requireActivity(), list)
val listView = v.findViewById<ListView>(R.id.list_view_groups) // << Set listView in a variable
listView.adapter = adapter
val list: ArrayList<GroupModelRetrieve> = arrayListOf()
database = FirebaseDatabase.getInstance()
databaseReference = database?.getReference("groups")!!.child("title")
val postListener = object : ValueEventListener{
override fun onCancelled(error: DatabaseError) {
Toast.makeText(requireContext(), "Fail to get data.", Toast.LENGTH_SHORT).show();
}
override fun onDataChange(snapshot: DataSnapshot) {
val data = snapshot.getValue()
val item = GroupModelRetrieve(data.toString())
list.add(item)
adapter.notifyDataSetChanged() // <<<<<<< Here is the change
}
}
databaseReference!!.addValueEventListener(postListener)
Also I suggest using addListenerForSingleValueEvent() instead of addValueEventListener() in case you need the list only once without the need to real-time updates

Related

When i get 10 data next 10 data is downloading but the previous 10 data is disappear how can i fix?(I think something wrong with arraylist)

This is my OnCreateActivity(I didn't put any more to avoid confusion)............................................................................................................................
auth= FirebaseAuth.getInstance()
adapters= ImageAdp(ArrayList())
binding.idRLWallpapers.adapter=adapters
getUsers(null)
override fun onScrolled(recyclerView: RecyclerView, dx: Int, dy: Int) {
var linearLayoutManager:LinearLayoutManager= recyclerView.layoutManager as LinearLayoutManager
var currentItems=linearLayoutManager.childCount
total_item=linearLayoutManager.itemCount
var lastVisibleitem=linearLayoutManager.findFirstVisibleItemPosition()
if(!isLoadingEDMT&&total_item<=lastVisibleitem+ITEM_COUNT){
// misLoad=true
getUsers(adapters.lastItemId())
isLoadingEDMT=true
binding.bottomPB.visibility=View.GONE
isLoad=false
}
}
})
This is how i am fetching data from firebase database .
private fun getUsers(nodeId:String?) {
if (nodeId==null){
Query = database.orderByKey().limitToFirst(ITEM_COUNT)
}
else{
Query = database.orderByKey().startAfter(nodeId).limitToFirst(ITEM_COUNT)
}
Query.addValueEventListener(object : ValueEventListener {
override fun onDataChange(snapshot: DataSnapshot) {
var arrayLists=ArrayList<imagemodel>()
if (snapshot.hasChildren()) {
for (data in snapshot.children) {
val image = data.child("url2").value.toString()
val name = data.child("voice1").value.toString()
val childname = data.child("childname").value.toString()
val id = data.child("id").value.toString()
val model = imagemodel(image, name,
arrayLists.add(model)
}
//adapters= ImageAdp(arrayList)
//binding.idRLWallpapers.adapter=adapters
adapters.addAll(arrayLists)
This is my RecyclerView Adapter(I didn't put any more to avoid confusion)
fun addAll(emp:List<imagemodel>){
var initialSize= myarraylist.size
myarraylist.addAll(emp)
notifyDataSetChanged()
}
fun lastItemId(): String? {
return myarraylist.get(myarraylist.size-1).uid
}
Thank you for your time
As i understand, you are initializing your adapter in OnCreate and trying to initialize again for every 10 element in down below, and last one replaces the previous one.
Initialize adapter with empty arraylist in OnCreate:
auth= FirebaseAuth.getInstance()
//binding.idRLWallpapers.adapter= ImageAdp(arrayList)
adapters= ImageAdp(ArrayList()) // like this
binding.idRLWallpapers.adapter=adapters
getUsers(null)
Turn your arrayList to local list to become empty for every 10 item.
Query.addValueEventListener(object : ValueEventListener {
override fun onDataChange(snapshot: DataSnapshot) {
var arrayList=ArrayList<imagemodel>() // like this
Delete below 2 lines to prevent recreate:
//adapters= ImageAdp(arrayList) // You did this in OnCreate
//binding.idRLWallpapers.adapter=adapters // remove these 2 lines
//inside Query.addValueEventListener
adapters.addAll(arrayList)
These should work, if not i am gonna need more of your code to understand it properly.
Declare your array list here .Then Add it to adapter
Query.addValueEventListener(object : ValueEventListener {
override fun onDataChange(snapshot: DataSnapshot) {
var arrayList=ArrayList<imagemodel>()
//your codes as it is
if (snapshot.hasChildren()) {
for (data in snapshot.children) {
val image = data.child("url2").value.toString()
val name = data.child("voice1").value.toString()
val childname =
data.child("childname").value.toString()
val id = data.child("id").value.toString()
val model = imagemodel(image, name, childname, id)
arrayList.add(model)
}
}
adapter.addAll(arrayList)
adapter.notyfyDataSetHasChanged()
}

MutableList remaining empty (?) even though i'm populating it

I'm trying to populate a mutable list so that I can use it for a recycler view. Unfortunately, although (i think) I'm populating the list, it's still remaining empty and the recycler view is not working (and I imagine it's because of the list issue). Please see below for the code:
private val newList: MutableList<NewListModel> = mutableListOf()
private val oldList = retrieveOldList()
private fun retrieveAndPopulate() {
for (i in 0 until oldList.size){
val oldItem = oldList[i]
val itemOne = oldItem.itemOne
val itemTwo = oldItem.itemTwo
val itemThree = oldItem.itemThree
val itemFour = oldItem.itemFour
val newItemData =
NewListModel(
itemOne, itemTwo, itemThree, itemFour
)
newList.add(newItemData)
Log.d(
"RetrieveData",
"${newItemData.itemOne} has been added to the list."
)
}
}
The class below is for the "NewListModel"
#Keep
#IgnoreExtraProperties
data class NewListModel (
var itemOne: String ?= null,
var itemTwo: String ?= null,
var itemThree: String ?= null,
var itemFour: String ?= null,
)
Below is how i try to populate the "oldList"
fun retrieveData(): MutableList<OldListModel> {
val list: MutableList<OldListModel> = mutableListOf()
val ref = FirebaseDatabase.getInstance().getReference("/storage")
ref.addValueEventListener(object : ValueEventListener {
override fun onDataChange(snapshot: DataSnapshot) {
if (snapshot.exists()) {
ref.get()
.addOnSuccessListener {
for (listItem in snapshot.children) {
val listItem = snapshot.getValue(OldListModel::class.java)
if (listItem != null) {
list.add(listItem)
}
}
}
} else {
Log.d(
"Data",
"Retrieving data was unsuccessful."
)
}
}
override fun onCancelled(error: DatabaseError) {
}
})
return list
}
It's probably worth mentioning that I'm getting the data from one mutable list and adding it to another. Any help is much appreciated
(below is how i try to populate the recycler view)
val newList = retrieveAndPopulate()
val recyclerView = findViewById<View>(R.id.recyclerView) as RecyclerView
val layoutManager = LinearLayoutManager(this)
recyclerView.layoutManager = layoutManager
val adapterAdapter = AdapterAdapter(newList)
recyclerView.adapter = adapterAdapter
Your problem is that you think you're running code sequentially when it's running asynchronously. See the numbered comments from your function to trace the order of execution:
fun retrieveData(): MutableList<OldListModel> {
// 1. Here you create a list
val list: MutableList<OldListModel> = mutableListOf()
val ref = FirebaseDatabase.getInstance().getReference("/storage")
// 2. Here a listener is added that will let you know LATER when the data is ready
ref.addValueEventListener(object : ValueEventListener {
// 4. LATER the data changed will get called
override fun onDataChange(snapshot: DataSnapshot) {
if (snapshot.exists()) {
ref.get()
.addOnSuccessListener {
// 5. EVEN LATER this listener is called with data
for (listItem in snapshot.children) {
val listItem = snapshot.getValue(OldListModel::class.java)
// 6. FINALLY - you add to a list that has long since stopped being relevant
if (listItem != null) {
list.add(listItem)
}
}
}
} else {
Log.d(
"Data",
"Retrieving data was unsuccessful."
)
}
}
override fun onCancelled(error: DatabaseError) {
}
})
return list // 3. Here you return the EMPTY list that was created
}
A solution - though likely not the best solution is to update your list once the callbacks complete:
private val theList = mutableListOf<YourDataModelType>
fun retrieveData(): { // No longer returning anything
// Remove this, no longer returning anything
// val list: MutableList<OldListModel> = mutableListOf()
val ref = FirebaseDatabase.getInstance().getReference("/storage")
ref.addValueEventListener(object : ValueEventListener {
override fun onDataChange(snapshot: DataSnapshot) {
if (snapshot.exists()) {
ref.get()
.addOnSuccessListener {
theList.clear() // Clear out existing data
for (listItem in snapshot.children) {
val listItem = snapshot.getValue(OldListModel::class.java)
if (listItem != null) {
theList.add(listItem)
}
}
// Since you're using Kotlin, you could use a map,
// but that's unrelated to this issue
// val list = snapshot.children.map { getValue(...) }.filterNotNull()
// Now that we have a full list here, update:
updateAdapterWithNewData(theList)
}
} else {
Log.d(
"Data",
"Retrieving data was unsuccessful."
)
}
}
override fun onCancelled(error: DatabaseError) {
}
})
}
Where updateAdapterWithNewData is a function you write to do as it says.
Please read up on asynchronous programming and make sure you understand how the code is flowing when using callbacks / listeners in frameworks like Firebase.
The issue that I had was with regards to not using callbacks while trying to access data in an onSuccessListener. This was causing the list not to be updated at all.
After a day of scrolling on the internet, I finally found these solutions:
Solution: link
Extension to the solution: link
This solved my problem and I hope it solves yours too!

Firebase to Kotlin Fragment

Is there any way to retrieved selected data in Firebase to a fragment in Kotlin? Not all data only selected row.
I'm new to Kotlin. Please help me.
firstly user login to the system. for this I checked the user name from Firebase. it works properly. But after that, I want to retrieve data of that username into a fragment. In one activity I add five fragments. I need to load all data of that user into one Fragment.
for example in this abi is a username and I need to load all data of only that username into one fragment.
Firebase data
Inside of abi
here's what I added.
val rootRef = FirebaseDatabase.getInstance().reference
val userRef = rootRef.child("User").child(sessionId)
val valueEventListener = object : ValueEventListener {
override fun onDataChange(dataSnapshot: DataSnapshot) {
val name = dataSnapshot.child("fullName").getValue(String::class.java)
val age = dataSnapshot.child("age").getValue(String::class.java)
val phone = dataSnapshot.child("phoneNo").getValue(String::class.java)
val bank = dataSnapshot.child("bankAccNo").getValue(String::class.java)
val password = dataSnapshot.child("passwordRegister").getValue(String::class.java)
nameText.setText(name)
ageText.setText(age)
phoneText.setText(phone)
bankText.setText(bank)
passwordText.setText(password)
}
override fun onCancelled(error: DatabaseError) {
Log.d("TAG", error.getMessage())
}
}
userRef.addListenerForSingleValueEvent(valueEventListener)
To get the data from the Firebase Realtime Database that corresponds only to the abi user, please use the following lines of code:
val rootRef = FirebaseDatabase.getInstance().reference
val userRef = rootRef.child("User").child("abi")
val valueEventListener = object : ValueEventListener {
override fun onDataChange(dataSnapshot: DataSnapshot) {
val name = dataSnapshot.child("fullName").getValue(String::class.java)
Log.d("TAG", name)
}
override fun onCancelled(databaseError: error) {
Log.d("TAG", error.getMessage()) //Don't ignore potential errors!
}
}
userRef.addListenerForSingleValueEvent(valueEventListener)
In the same way, you can also get the values of the other fields. The result in the logcat will be:
Abilashini

Display data from Firebase Realtime Database

Created next structure in my database, and now want to display data in my list
Tried to add next code in onViewCreated:
databaseReference = FirebaseDatabase.getInstance().reference
val wordsRef = databaseReference?.child("talk-6e3c0")?.child("words")
val valueEventListener = object : ValueEventListener {
override fun onDataChange(dataSnapshot: DataSnapshot) {
topWordsList.clear()
for (wordsSnapshot in dataSnapshot.children) {
val topWord = wordsSnapshot.getValue(TopWord::class.java)
topWord?.let { topWordsList.add(it) }
}
}
override fun onCancelled(databaseError: DatabaseError) {
Log.d("some", "Error trying to get targets for ${databaseError.message}")
}
}
wordsRef?.addListenerForSingleValueEvent(valueEventListener)
Method onDataChanged was called, but i can't get name for example.
My model:
data class TopWord(
val name: String = "",
val description: String = ""
)
You aren't getting something because you are adding the name of your project as a child in the reference and there is no need for that. So please change the following line of code:
val wordsRef = databaseReference?.child("talk-6e3c0")?.child("words")
to
val wordsRef = databaseReference?.child("words")
I just removed the call to .child("talk-6e3c0")?.

Populating Data Class via Simple Firebase Calls

Running into an error I have been researching and attempting to fix for the past couple weeks. There are tons of suggestions out there and I've tried at least half a dozen with the same result each time.
How does Kotlin access Firebase data and populate a very simple data class?
Error: com.google.firebase.database.DatabaseException:
Can't convert object of type java.lang.String to type com.touchtapapp.handsofhope.LandingTextTitles
Read about suggestions to first convert to a Map and then to my custom data class... attempted this, successfully created the Mapped values w/ correct data... but ran into the exact same error when sending the Mapped values to the customs data class (LandingTextTitles).
Current code:
Data Model Class
data class LandingTextTitles(
val subTitle: String,
val title: String
)
Method to retrieve data from firebase
private fun initTitles() {
val ref = FirebaseDatabase.getInstance().getReference("/landing")
ref.addListenerForSingleValueEvent(object: ValueEventListener {
override fun onDataChange(p0: DataSnapshot) {
p0.children.forEach {
val titles = it.getValue(LandingTextTitles::class.java)
}
}
override fun onCancelled(p0: DatabaseError) {
// Handle Cancelled Data
}
})
// Log the titles value to see if data passed correctly
Log.d("Titles", titles.toString())
}
When I log out something like Log.d(it.toString()), I see the keys and values just fine. What am I doing wrong here?
EDIT:
Firebase data snapshot
EDIT 2:
If we use Log.d("Titles", it.toString()), we get the following:
D/Titles: DataSnapshot { key = subTitle, value = Start Here. }
D/Titles: DataSnapshot { key = title, value = Facing unexpected problems? }
If you have the following database:
landing
randomId
subTitle : "Awesome"
title : "Developer Team"
Then you can retrieve title and subTitle by doing the following:
private fun initTitles() {
val ref = FirebaseDatabase.getInstance().getReference("/landing")
ref.addListenerForSingleValueEvent(object: ValueEventListener {
override fun onDataChange(p0: DataSnapshot) {
p0.children.forEach {
val title = it.child("title").getValue(String::class.java)
val subTitle = it.child("subTitle").getValue(String::class.java)
}
}
override fun onCancelled(p0: DatabaseError) {
// Handle Cancelled Data
}
})
// Log the titles value to see if data passed correctly
Log.d("Titles", titles.toString())
}
If you want to use the data class, then change this:
override fun onDataChange(p0: DataSnapshot) {
p0.children.forEach {
val titles = it.getValue(LandingTextTitles::class.java)
}
into this:
override fun onDataChange(p0: DataSnapshot) {
val titles = p0.getValue(LandingTextTitles::class.java)
}

Categories

Resources