I am reading data from Firebase Cloud Firestore and populating them into my UI. Below is my data structure:
Below is my code to read the data from the Cloud Firestore and populate the UI. I am noticing that for my TextView, the item is briefly null before it displays the "Test Q 2." Am I reading data incorrectly? After a split second, the TextView populates the question from Firebase, but I find it odd that it is briefly null and the null is visible in the UI:
mStoreBaseRef = FirebaseFirestore.getInstance();
mStoreSelectedPollRef = mStoreBaseRef.collection(POLL_LABEL).document(pollID);
mStoreSelectedPollRef.get().addOnSuccessListener(new OnSuccessListener<DocumentSnapshot>() {
#Override
public void onSuccess(DocumentSnapshot documentSnapshot) {
Poll selectedPoll = documentSnapshot.toObject(Poll.class);
String pollQuestion = selectedPoll.getQuestion();
mPollQuestion.setText(pollQuestion);
mPollQuestion.setTypeface(null, Typeface.BOLD);
}
});
Data is loaded from Firestore asynchronously. Depending on your connection speed and the state, it may take from a few hundred milliseconds to a few seconds before that data is available.
So the brief time before the poll is populated is the expected behavior. If this is confusing for your users, you might want to populate it with good default values, or show a "loading, please wait" type message.
Related
I am new to android studio and firebase. I am trying to save a list of people to firebase like this. Idea is that the logged in user should be able to save information about some people.
String userId = user.getCurrentUser().getUid();
databaseReference.child("users").child(userId).child("savedPersons").child("name").setValue(nameTxt);
databaseReference.child("users").child(userId).child("savedPersons").child("surname").setValue(surnameTxt);
databaseReference.child("users").child(userId).child("savedPersons").child("gender").setValue(genderTxt);
databaseReference.child("users").child(userId).child("savedPersons").child("ageTxt").setValue(ageTxt);
It does not surprise me that it deletes the previous saved person when i save another one but i don't know how to save all of them. I have this in my firebase but i need multiple saved users. How do i do it ?
Firebase screenshot
If you want to save multiple people in a list in the database, you'll want to call push:
String userId = user.getCurrentUser().getUid();
DatabaseReference newRef = databaseReference.child("users").child(userId).child("savedPersons").push(); // 👈
newRef.child("name").setValue(nameTxt);
newRef.child("surname").setValue(surnameTxt);
newRef.child("gender").setValue(genderTxt);
newRef.child("ageTxt").setValue(ageTxt);
This will create a new child node under savedPersons each time you call push(). To learn more on this, see the Firebase documentation on appending data to a list.
Note that calling setValue for each property is wasteful, and may lead to unexpected behavior down the line. I recommend putting all values in a map, and then adding them all with one call to setValue:
Map<String, Object> values = new Map<>();
values.put("name", nameTxt);
values.put("surname", surnameTxt);
values.put("gender", genderTxt);
values.put("ageTxt", ageTxt);
newRef.setValue(values);
How can I change multiple documents? I have 2 collections firestore. One (users) is for user account (email, name, etc).
To second collections (dashboard) users can add some message to a board. In this second collection is name, category, time etc.
What I want to do is when someone change his name or faculty in account, it will also change in second collection for each his comment so it will show up to date information
DocumentReference documentReference = fStore.collection("users").document(user.getUid());
Map<String, Object> edited = new HashMap<>();
edited.put("email",email);
edited.put("smallName",StringUtils.unaccent(profileName.getText().toString()).toLowerCase());
edited.put("fullName",profileName.getText().toString());
edited.put("fakulta",mySpinner.getSelectedItem().toString());
documentReference.update(edited).addOnSuccessListener(new OnSuccessListener<Void>() {
#Override
public void onSuccess(Void aVoid) {
Toast.makeText(EditProfile.this, "Profile data are changed", Toast.LENGTH_SHORT).show();
//startActivity(new Intent(getApplicationContext(),MainActivity.class));
finish();
}
Firestore
Is there any way to do it without changing the whole structure of my app?
To update the user names in the comment docs, you'll need to:
Query the collection to find the comments by the user who updated their name. If you stored the UID for each user in the comment document, this would look something like fStore.collection("dashboard").where("uid", "==", "theUidOfTheUserWhoUpdatedTheirName"). If you didn't store their UID, you'll have to query on the old value of their name instead, but the code will be similar.
Loop over the query results and update each document in turn. If you have a lot of these, you may want to read about the fastest way to do this here: What is the fastest way to write a lot of documents to Firestore?
I want to see if a value is in my firebase database, the user will provide the value thereafter I want to say if the value is present then move to the next activity.
Data in firebase is retrieved by adding a asynchronous listener to a database reference. So you have to change the way you are used to retrieve data from other data sources like MySQL...
Thus, define the reference to the part of firebase database where the user is going to insert its data and attach listener to it. In the listener write your code to go to the next activity.
For example:
final FirebaseDatabase database = FirebaseDatabase.getInstance();
DatabaseReference ref = database.getReference("server/NodeOfTheUser");
ref.addValueEventListener(new ValueEventListener() {
#Override
public void onDataChange(DataSnapshot dataSnapshot) {
//your code to go to the next activity
}
});
For more info: firebase documentation.
I want to query my Workout Collection for the latest workout from a routine. Meaning I query with whereEqualTo my routineKey, order it by the Started TimeStamp in descending order and then limit to 1 and then take the this 1st Key/Id of the Workout.
However this does not work. whereEqualTo and orderBy work separately but not combined. What am I doing wrong?
fm.getColRefWorkout().whereEqualTo("routineKey", routineKey).orderBy("startTimeStamp", Query.Direction.DESCENDING).limit(1).get().addOnSuccessListener(new OnSuccessListener<QuerySnapshot>() {
#Override
public void onSuccess(QuerySnapshot documentSnapshots) {
workoutKey = documentSnapshots.getDocuments().get(0).getId();
//To stuff with this workoutKey
}
});
This query will not work unless you create an index for it. This can be done, by creating it manually in your Firebase Console or if you are using Android Studio, you'll find in your logcat a message that sounds like this:
FAILED_PRECONDITION: The query requires an index. You can create it here: ...
You can simply click on that link or copy and paste the URL into a web browser and your index will be created automatically.
I am trying to create a dynamic Query by storing a value in the Cloud Firestore that represents a minimum Epoch. Let's call this value "filter_value":
I am successfully reading this value by calling, from .onStart(),
mStoreBaseRef.collection("epoch_filter").addSnapshotListener(new EventListener<QuerySnapshot>() {
#Override
public void onEvent(QuerySnapshot querySnapshot, FirebaseFirestoreException e) {
for (DocumentSnapshot z : querySnapshot){
Epoch epoch = z.toObject(Epoch.class);
filterEpochValue = (long) epoch.getFilter_value();
Log.v("X_VALUE", filterEpochValue.toString());
}
}
});
I have logged the value and confirmed that it has been read successfully.
I then have a collection of Polls that each have an epoch. I want to use the filter variable from above to perform a Query on these polls, based on their respective Epoch, so that I can only view the polls greater than my "filter_value."
I am querying using the below:
Query queryStore = FirebaseFirestore.getInstance()
.collection("Polls")
.whereGreaterThan("epoch", filterEpochValue)
.orderBy("vote_count");
FirestoreRecyclerOptions<Poll> storeOptions = new FirestoreRecyclerOptions.Builder<Poll>()
.setQuery(queryStore, Poll.class)
.build();
and receiving the following:
java.lang.IllegalArgumentException: Invalid Query. You can only perform equality comparisons on null (via whereEqualTo()).
at com.google.android.gms.internal.zzenx.zza(Unknown Source)
at com.google.firebase.firestore.Query.zza(Unknown Source)
at com.google.firebase.firestore.Query.whereGreaterThan(Unknown Source)
at com.troychuinard.fanpolls.Fragment.TrendingFragment.onStart(TrendingFragment.java:181)
at android.support.v4.app.Fragment.performStart(Fragment.java:2287)
You're not showing the rest of your code, but I suspect that you're building your query without waiting for the snapshot listener callback to complete. The method addSnapshotListener is asynchronous, meaning it returns immediately before the results are ready. You have to plan for this. That means you should not continue with your query that depends on filterEpochValue until that value becomes available. The first time it becomes available is in your callback, so you should start your query there.
Please read here for more information about why Firebase APIs are asynchronous and what to expect from them.