Im using Firebase database to store my users scores games , at the end of the game users can see the final results of every members of the party
My users data and their scores are stored at 2 different places
here how looks my structure in Firebase.
Posts
-KLpcURDV68BcbAvlPFy
user_id: "KLpcURDV68BcbAvlPFy"
score: "A"
-asdasdasddsad
user_id: "asdasdasddsad"
score: "B"
Users
-KLpcURDV68BcbAvlPFy
id: "KLpcURDV68BcbAvlPFy"
name: "Jordan"
-asdasdasddsad
id: "asdasdasddsad"
name: "Tyler"
So I load first Id from Child (Posts ) inside an Arraylist and after I user the ListIterator to load data for every id in the Child(Users ) .
My question is simple . How can I pause a ListIterator
I have an Firebase onDataChanged Load inside a My ListIterator , it return null because my list finish faster than my Firebase load , How can I make my List wait for my Firebase database to load necessary data and then resume itself ?
My code
for (ListIterator<String> it = list.listIterator(); it.hasNext(); i++) {
String UserUid= it.next();
LoadataValue(UserUid, new OnObjectExistListener<String>() {
#Override
public void onDataChanged(Data userData) {
ListIterator must resume here
}
});
ListIterator must pause Here
}
You cannot pause a list iterator they way you want it to. Let me explain a little bit.
Firebase gets the data over the internet in a separate background thread and it should take some time to trigger that onDataChanged method whereas your list iterator might be running in the main thread. Hence, you will always have to wait for the background thread to be completed and return some data to your main thread to be able to show them. You can achieve the behavior in many different ways.
It looks like you are trying to get all the user details from the firebase. I assume, the simplified structure of your firebase database looks like the following.
users:
user1:
userDetails:
name: Everyone
user2:
userDetails:
name: Needs
user3:
userDetails:
name: some
user4:
userDetails:
name: help
You can try getting all the values at once from the users node, and store them locally (maybe inside a List<User>). Then once the list of users are downloaded correctly in your onDataChange function, trigger your list iterator in a separate method so that it can go over that locally stored list and provide you the results that you want.
Here's a pseudo implementation.
// Get a reference to your users
final FirebaseDatabase database = FirebaseDatabase.getInstance();
DatabaseReference ref = database.getReference("your-firebase-url/users");
// Attach a listener to read the data from your firebase database
ref.addValueEventListener(new ValueEventListener() {
#Override
public void onDataChange(DataSnapshot dataSnapshot) {
List<User> users = dataSnapshot.getValue(User[].class);
callAFunctionThatRunsThroughThisListOfUsers(users);
}
});
Related
I'm developing an app that has a video and an article feed. I implemented swipe refresh layout. Whenever user swipes it, it loads last 5 video datas from Firebase.
My database is like this (it's not much data) =>
Swipe refresh layout listener =>
mSwipeRefreshLayout.setOnRefreshListener(() -> {
manager.scrollToPosition(0);
refreshVideoFeed();
});
And refreshVideoFeed method triggers this =>
Query query = myRef.orderByChild("videoDate").limitToLast(5);
query.addListenerForSingleValueEvent(new ValueEventListener() {
#Override
public void onDataChange(#NonNull DataSnapshot dataSnapshot) {
..................
It works fine. However, I realized that app is using lots of data when i looked at Realtime Database dashboard (even app is not in product)
Then I opened Profiler in Android Studio to see what is going on. I ordered by child 'videoDate' and got last 5 videos. It costs 76 KB for refreshing video feed.
Then again I ordered by child 'videoDate' and got last 20 videos. Again it costs 77KB !
Also, I implemented the same mechanism for article feed. I have 236 articles in my realtime database. Whenever user swipes, it loads 10 articles and it costs 3,6 MB!
I wonder why this is happening and how to avoid that. It seems Firebase SDK fetchs all Videos to client and then filters them. But I want to fetch only specific range of data that I specified.
Ordering and filtering data is only done on the Firebase servers if there's an index defined on the property/value you filter on. If there's no index, the server sends all data to the client, which then orders and filters it. There should a quite explicit message in the log output when this happens.
To define an index, you go to the security rules panel in your Firebase console and on the node that myRef points to add an .indexOn property. Say myRef refers to /articles, it'd look something likeL
{
"rules": {
"articles": {
".indexOn": "videoDate"
}
}
}
If you order/filter on different properties, you can add multiple indexes:
".indexOn": [ "videoDate", "category" ]
So I am keeping track of a users taps on the screen and I have the user sign up with their email. However, when it comes to using the Firebase Database I am lost. I am not sure, how to save integers and then it load up when the user logs in. Can someone point me in the right direction?
I have watched a ton of videos and none show how to store information with an integer.
You don't need to do anything special for storing a integer or any other value in the Firebase DB.
You can use the uid of the current user and store the pojo/model directly into the the firebase DB.
For example, this can be your java model class:
public class Model {
private int tapCount=0;
public int getTapCount() {
return tapCount;
}
public void setTapCount(int tapCount) {
this.tapCount = tapCount;
}
}
When you want to insert the tap count into the Firebase db. You need to take the previous tap counts and add it with the current count update/create the Model object and set it into the Firebase db in the uid.
FirebaseDatabase.getInstance().getReference()
.child("user")
.child(FirebaseAuth.getInstance()
.getCurrentUser()
.getUid())
.setValue(model);
This code will insert the model under the user key and under user unique id.
Thanks,
Hope it helps.
I saved the data into Fire base but when I retrieve it. The data is not in the sequence.
Here Data Is Saved In Accurate Sequence:
But when I retrieve data lost its sequence:
Here is my code for retrieving Data
DatabaseReference ref = FirebaseDatabase.getInstance().getReference("Users").child(Autho_User.getUid()).child("Data");
ref.addListenerForSingleValueEvent(
new ValueEventListener() {
#Override
public void onDataChange(DataSnapshot dataSnapshot) {
System.out.println(" Value = "+dataSnapshot.toString());
}
(Printed it just to check values) Data is not in the sequence even I get it through
dataSnapshot.getvalue();
Hope so you got my question. I need the data in sequence
Firebase stores JSON data. By definition the children under a node in JSON are unordered. It is only when the data is displayed or retrieved that it gets an order. So the first screenshot that you show is just the order in which the Firebase Database console display it.
If you want to get the data in a specific order in your application, you need to do two things:
Execute a query that returns the data in that order.
Ensure that your code maintains that order.
The code you shared does neither 1 nor 2, so the order in which the data is printed is anybody's guess. Usually it will be in lexicographical order of the keys, but it is undefined.
To learn how to order/filter data, read the Firebase documentation on ordering and filtering. To learn how to maintain the order of items when you use a ValueEventListener, read the Firebase documentation on listening for value events. When you combine these two, you get:
DatabaseReference ref = FirebaseDatabase.getInstance().getReference("Users").child(Autho_User.getUid()).child("Data");
Query dataOrderedByKey = ref.orderByKey();
dataOrderedByKey.addListenerForSingleValueEvent(new ValueEventListener() {
#Override
public void onDataChange(DataSnapshot dataSnapshot) {
for (DataSnapshot childSnapshot: dataSnapshot.getChildren()) {
System.out.println("Key = "+childSnapshot.getKey()+" Value = "+childSnapshot.toString());
}
}
...
This is an incredibly common mistake/question, so here are some previous questions for reference:
How to Convert Firebase data to Java Object...?
Ordering of data with Firebase Android
Firebase returning keys of child node in different orders on different devices/Android versions
How to sort by children key value in firebase?
Firebase .getvalue not in the same order as database
Order by date in negative timestamp is not working in Firebase
I have a node that I refresh every three days with some key-value pairs in my firebase realtime database. I want my app to get the new values only when I make changes in this node (so about every three days). I currently use this code to test :
mFirebaseDatabase.getReference().child("test").addValueEventListener(new ValueEventListener() {
#Override
public void onDataChange(DataSnapshot dataSnapshot) {
Long tsLong = System.currentTimeMillis();
Log.d("thatsdatasnapshot", "thatsdatasnapshot = " + tsLong.toString());
Log.d("thatsdatasnapshot", "thatsdatasnapshot = " + dataSnapshot.toString());
}
My issue is that my logs in this listener print very often even I don't change anything in my node, for example everytime I start the app. So I guess that all the values of my node are downloaded "very often", not only when I make change in my database. Am I wrong ? How to download the values of my node only when there is a change ? I thought it was what addValueEventListener() should do but I have a doubt when I see my logs printed so often.
Thank you,
Alex
The method addValueEventListener is only triggered when values in the realtime db change during your current run of the app, such as for every mRef.push() or mRef.child("someChild").setValue() method call in your app.
I had almost the same kind of problem with firebase realtime database and in the end, i resorted to creating an AsyncTask to update what you have to update during your app's runtime.
What you have to do is create an AsyncTask and make a REST call to your Firebase Database, and use it to update.
I've used the Real-Time Database with this setup:
->users
->uid
->name
->email
->other info
If I wanted to save the user data I would use my User class and then set the object in the database like this:
//assume variables have already been declared...
mFirebaseAuth = FirebaseAuth.getInstance();
mFirebaseUser = mFirebaseAuth.getCurrentUser();
User user = new User(name, email, other values...);
mDBRef.child("users").child(mFirebaseUser.getUid()).setValue(user);
I tried it and it works fine.
But how can I retrieve these values from the database? For instance, once I set a User object as shown above, I may want to retrieve the user's email. I don't mean getting the email through the sign-in provider. I want the email through the real-time database. I've tried working this out for a while now but the documentation isn't helping much. All it shows is to setup listeners in order to wait for changes to the data. But I'm not waiting for changes, I don't want a listener. I want to directly get the values in the database by using the keys in the JSON tree. Is this possible via the real-time database? If so, how can it be done because either the documentation doesn't explain it or I'm just not understanding it. If not possible, am I supposed to be using the Storage database or something else? Thanks.
Firebase uses listeners to get data. That is just the nature of how it works. Although, you can use a single event listener (the equivalent of just grabbing the data once). It will fire immediately and get the data, and will not fire ever again. Here's a code example to get the current user's email:
//Get User ID
final String userId = getUid();
//Single event listener
mDatabase.child("users").child(userId).addListenerForSingleValueEvent(
new ValueEventListener() {
#Override
public void onDataChange(DataSnapshot dataSnapshot) {
// Get user value
User user = dataSnapshot.getValue(User.class);
//user.email now has your email value
}
});