Android App Development - Firebase Database - android

I'm building an activity in an app where users can upload a post, and other users in the app can view the post.
I built a function called loadPost()
This function will take what's there in the database and load it in my View.
Unfortunately, I'm facing an error with the
.addValueEventListener(ValueEventListener{
It's telling me that the interface needs a constructor.
here's the function:
//*******************************************************
//Load posts to the screen from the database
//****************************************************
fun loadPost(){
myRef.child("posts")
.addValueEventListener(ValueEventListener{
override fun onDataChange(#NonNull dataSnapshot: DataSnapshot?) {
try {
postElements.clear()
postElements.add(Post("0","him","url","add"))
postElements.add(Post("0","him","url","ads"))
//Hashmap : Key and value (represents the post and node)
var td= dataSnapshot!!.value as HashMap<String,Any>
for(key in td.keys){
var post= td[key] as HashMap<String,Any>
postElements.add(Post(key,
post["text"] as String,
post["postImage"] as String
,post["userUID"] as String))
}
adpater!!.notifyDataSetChanged() //notify when there's an update in the adapter
}catch (ex:Exception){}
}
override fun onCancelled(p0: DatabaseError?) {
}
})
}

this is how the constructor of a ValueEventListener should look alike:
object : ValueEventListener {
override fun onDataChange(dataSnapshot: DataSnapshot) {
}
}
which means, that you have to replace this one line
.addValueEventListener(ValueEventListener {
with:
.addValueEventListener(object : ValueEventListener {
see https://youtrack.jetbrains.com/issue/KT-7770 (concerning the code-converter)

Related

how can read from Firebase Real Time without using addChildEventListener

in my case when login to the application
need to get user profile from realTime Database by UID
in docs must be using addValueEventListener to read from RealTime DB
//how can get value direct from real-time firebase if I have id for obj
fun loginByEmail(email: String, password: String) {
firebaseAuth.signInWithEmailAndPassword(email, password).addOnCompleteListener { task ->
if (task.isSuccessful) {
getUserValueFromDB(firebaseAuth.currentUser!!.uid, email)
}
}
}
//My problem is here is not access to this method
private fun getUserValueFromDB(uid: String, email: String) { //todo
databaseReference.child("Users").addValueEventListener(object : ValueEventListener {
override fun onDataChange(snapshot: DataSnapshot) {
for (snap in snapshot.children) {
var data = snap.getValue(User::class.java)
if (data?.id == uid) {
prefs.userImage = data.image!!
GlobalScope.launch {
_loginStatus.emit(true)
}
}
}
}
override fun onCancelled(error: DatabaseError) {
TODO("Not yet implemented")
}
})
}
If you want to read the data from one specific user from your database, you can do so by using a query.
private fun getUserValueFromDB(uid: String, email: String) {
var query = databaseReference.child("Users").orderByChild("id").equalTo(uid)
query.addValueEventListener(object : ValueEventListener {
override fun onDataChange(snapshot: DataSnapshot) {
...
The rest of your code can stay the same, you'll just be loading a lot less data.

Firebase Realtime Database and Kotlin Coroutines

I am a beginner and currently working on an android app in Kotlin that gets data from TMDb
API and uses Firebase Realtime Database for storing and retrieving data.
I use Kotlin Coroutines to get data from TMDb API but I am not sure if I should use coroutines for storing or retrieving data from Firebase Realtime Database.
I am hoping that Firebase automatically does the work done by Kotlin coroutines.
Here is one of the Firebase operations that I want to perform : (retrieve object from database)
firebaseDatabase = Firebase.database
dbReference = firebaseDatabase.getReference("users/$uid")
val dbListener = object : ValueEventListener {
override fun onDataChange(dataSnapshot: DataSnapshot) {
// Get Post object and use the values to update the UI
val fobject = dataSnapshot.getValue<TvFirebase>()
Log.v("utk", "tv show name is " + fobject!!.name)
// ...
}
override fun onCancelled(databaseError: DatabaseError) {
// Getting Post failed, log a message
Log.w("utk", "onCancelled", databaseError.toException())
// ...
}
}
val tvReference = firebaseDatabase.getReference("users/$uid/tv/236")
tvReference.addValueEventListener(dbListener)
So do I need to use Kotlin Coroutines with Firebase Realtime Database?
I'm adding some new features in my old project using both "Realtime database" and "Firestore".
Since firestore supports "await" suspend function on Coroutines I searched the same for Realtime database. Coroutines are great if you don't mix suspend and callback function..
End up to do it myself. I didn't try yet the code below but it should work.
Note: Some features are still marked as ExperimentalCoroutinesApi since 1.2.0, so be careful if it changes in futur releases.
sealed class RealtimeDatabaseValueResult {
class Success(val dataSnapshot: DataSnapshot): RealtimeDatabaseValueResult()
class Error(val error: DatabaseError): RealtimeDatabaseValueResult()
}
/**
* Perform a addListenerForSingleValueEvent call on a databaseReference in a suspend function way
* #param onCancellation action to perform if there is a cancellation
*/
#ExperimentalCoroutinesApi
suspend fun DatabaseReference.awaitSingleValue(onCancellation: ((cause: Throwable) -> Unit)? = null) = suspendCancellableCoroutine<RealtimeDatabaseValueResult> { continuation ->
val valueEventListener = object: ValueEventListener{
override fun onCancelled(error: DatabaseError) {
continuation.resume(RealtimeDatabaseValueResult.Error(error = error), onCancellation)
}
override fun onDataChange(snapshot: DataSnapshot) {
continuation.resume(RealtimeDatabaseValueResult.Success(snapshot), onCancellation)
}
}
// add listener like you normally do
addListenerForSingleValueEvent(valueEventListener)
// in case the job, coroutine, etc. is cancelled, we remove the current event listener
continuation.invokeOnCancellation { removeEventListener(valueEventListener) }
}
Usage :
fun fetchUser(firebaseDatabase: FirebaseDatabase, userId: String){
CoroutineScope(SupervisorJob() + Dispatchers.Main.immediate).launch{
when(val result = firebaseDatabase.getReference("users").child(userId).awaitSingleValue()){
is RealtimeDatabaseValueResult.Success -> {
val dataSnapshot: DataSnapshot = result.dataSnapshot
// proceed action with dataSnapshot
}
is RealtimeDatabaseValueResult.Error -> {
val error: DatabaseError = result.error
// proceed action with error
}
}
}
}
It's not required to use coroutines with any Firebase API, but that can certainly make your development easier, if you do it correctly. However, coroutines are not compatible with Firebase listeners that report changed values over time. For those, you might want to use a LiveData or Flow.
Just add a minor change to your code.
From this...
firebaseDatabase = Firebase.database
dbReference = firebaseDatabase.getReference("users/$uid")
val dbListener = object : ValueEventListener {
override fun onDataChange(dataSnapshot: DataSnapshot) {
// Get Post object and use the values to update the UI
val fobject = dataSnapshot.getValue<TvFirebase>()
Log.v("utk", "tv show name is " + fobject!!.name)
// ...
}
override fun onCancelled(databaseError: DatabaseError) {
// Getting Post failed, log a message
Log.w("utk", "onCancelled", databaseError.toException())
// ...
}
}
val tvReference = firebaseDatabase.getReference("users/$uid/tv/236")
tvReference.addValueEventListener(dbListener)
To this...
val firebaseDatabase = FirebaseDatabase.getInstance().getReference("users/$uid")
firebaseDatabse.addChildEventListener(object: ChildEventListener {
override fun onChildAdded(snapshot: DataSnapshot, previousChildName: String?) {
Log.d("MainFragment", "Children $snapshot")
}
override fun onChildChanged(snapshot: DataSnapshot, previousChildName: String?) {}
override fun onChildRemoved(snapshot: DataSnapshot) {}
override fun onChildMoved(snapshot: DataSnapshot, previousChildName: String?) {}
override fun onCancelled(error: DatabaseError) {}
})
Dont forget to check this if its correct man ;)
You can use callBackFlow API to remove all of firebase callbacks.
Simple ex:
override suspend fun getSomething(): Flow<Long> = callbackFlow {
val valueListener = object: ValueEventListener{
override fun onCancelled(error: DatabaseError) {
close()
}
override fun onDataChange(snapshot: DataSnapshot) {
offer(snapshot.childrenCount)
}
}
currentUserId?.let { userId ->
firebaseRef?.child(userId)?.addValueEventListener(valueListener)
?: offer(0) }
awaitClose {
currentUserId?.let { userId ->
firebaseRef?.child(userId)?.removeEventListener(valueListener)
}
}
}

Retrieve data from Firebase on Android Studio

Can someone help me fix it?
Following code works without any error, however, it does not retrieve data from Firebase and show in the TextView.
private fun viewData() {
val postReference = FirebaseDatabase.getInstance().getReference("dataID")
val dbView= findViewById<TextView>(R.id.txtFdbData)
val postListener = object : ValueEventListener {
override fun onDataChange(dataSnapshot: DataSnapshot) {
val post = dataSnapshot.getValue(Post::class.java)
dbView.text=post?.postName
}
override fun onCancelled(databaseError: DatabaseError) {
}
}
postReference.addValueEventListener(postListener)
Toast.makeText(this,"Retrieved",Toast.LENGTH_LONG).show()
}
Above code is called when I tap the button 'btnView'
viewButton = findViewById(R.id.btnView)
viewButton.setOnClickListener {
viewData()
}
When I hit the button it shows the toast message 'Retrieved' and the default value given in the TextView (txtFdbData) is deleted (or may be replaced with an empty string?, I do not know).
Following is the post Class
data class Post (
val postName: String="",
val postDescription:String="")
I am working on Android Studio, using Kotlin and Firebase Realtime Database.
You query to database return list of items. So loop through it and try to get Post. Check below:
override fun onDataChange(dataSnapshot: DataSnapshot) {
dataSnapshot.children.forEach {childSnapshot ->
val post = childSnapshot.getValue(Post::class.java)
dbView.text=post?.postName
}
}
getReference("dataID") is not your data node it is your parent node.
Then you have to access their children using getChildren() method.
Change you on data change method with this.
override fun onDataChange(dataSnapshot: DataSnapshot) {
for (postSnapshot : dataSnapshot.getChildren()) {
val post = postSnapshot .getValue(Post::class.java)
dbView.text=post?.postName
}
}

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)
}

load posts from firebase

i m working over application connected with fire base here which retrieves data from db 'm getting error unresolved reference dataSnapshot in Homefrag.kt file and to be very precise in
//load posts from firebase
fun LoadPostFromFireBase(){...}
clean project=>rebuild=>invalidate cache
fun LoadPostFromFireBase(){
myRef.child("posts")
.addValueEventListener(object : ValueEventListener {
override fun onDataChange(p0: DataSnapshot ) {
try {
listOfPost.clear()
listOfPost.add(Post("0","him","url"," ","add","addPost"))
var td= dataSnapshot!!.value as HashMap<String,Any>
for(key in td.keys){
var post= td[key] as HashMap<String,Any>
listOfPost.add(Post(key,
post["postText"] as String,
post["postImageURL"] as String
,post["postDate"] as String
,post["personName"] as String
,post["personID"] as String))
}
adapter!!.notifyDataSetChanged()
}catch (ex:Exception){}
}
override fun onCancelled(p0: DatabaseError) {
}
})
}
getting unresolved dataSnapshot!
You're looking for something that does not exist. Look at what the function onDataChange is giving you through its parameters.
I don't know Kotlin, but I'm pretty sure looking at your syntax that you're receiving "p0" inside the onDataChange, but you're looking for the object dataSnapshot.
You can fix it by replacing
var td= dataSnapshot!!.value as HashMap<String,Any>
with
var td= p0!!.value as HashMap<String,Any>

Categories

Resources