How can I program a key in my FirebaseDatabase that is created by the userName. wText should then be the text: "" Value.
I try to create a key but when i run my app it removes all values in my database
The Code:
`
// getting text from our edittext fields.
String nameValue = userName.getText().toString();
String textValue = wText.getText().toString();
// below line is for checking whether the
// edittext fields are empty or not.
if (nameValue.isEmpty() && textValue.isEmpty()) {
// if the text fields are empty
// then show the below message.
Toast.makeText(AddTextActivity.this, "Please add some data.", Toast.LENGTH_SHORT).show();
return;
} else {
// else call the method to add
// data to our database.
addDatatoFirebase(nameValue, textValue);
finish();
}
}
});
}
private void addDatatoFirebase(String name, String wText) {
// below 3 lines of code is used to set
// data in our object class.
Messages.setuserName(name);
Messages.setText(wText);
// we are use add value event listener method
// which is called with database reference.
myRef.addValueEventListener(new ValueEventListener() {
#Override
public void onDataChange(#NonNull DataSnapshot snapshot) {
// inside the method of on Data change we are setting
// our object class to our database reference.
// data base reference will sends data to firebase.
myRef.setValue(text);
// after adding this data we are showing toast message.
Toast.makeText(AddTextActivity.this, "data added", Toast.LENGTH_SHORT).show();
}
#Override
public void onCancelled(#NonNull DatabaseError error) {
// if the data is not added or it is cancelled then
// we are displaying a failure toast message.
Toast.makeText(AddTextActivity.this, "Fail to add data" + error, Toast.LENGTH_SHORT).show();
}
}); `
It seems you might be using set() function to update data in firebase.
( in your case setValue(), I'm not sure if it is Firebase function or user defined function , Firebase uses set() method in almost in every SDK, not sure about Java SDK for Firebase )
Please note that set() will replace the existing value, or create a new key if there isn't any.
Use update() function instead of set()
Ways to Save Data
set - Write or replace data to a defined path, like messages/users/
update - Update some of the keys for a defined path without replacing all of the data
push - Add to a list of data in the database. Every time you push a new node onto a list, your database generates a unique key, like
messages/users//
transaction - Use transactions when working with complex data that could be corrupted by concurrent updates
refer the docs here
Related
I'm trying to retreive a custom User object from Firebase as follows:
getUserFromDB(loggedInUserEmail);
viewModel = new ViewModelProvider(this).get(UserViewModel.class);
viewModel.sendUser(loggedInUser);
//...
public void getUserFromDB(String userEmail) {
DocumentReference docRef = db.collection("users").document(userEmail);
docRef.get().addOnSuccessListener(documentSnapshot -> {
loggedInUser = documentSnapshot.toObject(User.class);
Log.d("User Login", documentSnapshot.getId() + " => " + documentSnapshot.getData());
Toast.makeText(MainActivity.this, "Login successful.", Toast.LENGTH_SHORT).show();
});
}
However, the user being retreived always has null attributes.
Here's a screenshot from when I was debugging.
Note: I made sure my User class has a public empty constructor and all the attributes have a getter method.
Loading the user from the database is an asynchronous operation. While the data is being loaded, the main code continues and your viewModel.sendUser(loggedInUser) executes before the data is loaded. Then the success callback is fired and sets loggedInUser, but by that time the view model has already been initialized with the wrong value.
The rule is always quite simple: any code that needs data from the database, needs to be inside the success listener (or be called from there). So something like:
public void getUserFromDB(String userEmail) {
DocumentReference docRef = db.collection("users").document(userEmail);
docRef.get().addOnSuccessListener(documentSnapshot -> {
loggedInUser = documentSnapshot.toObject(User.class);
// 👈 Initialize ViewModelProvider here
viewModel = new ViewModelProvider(this).get(UserViewModel.class);
viewModel.sendUser(loggedInUser);
});
}
Also see:
How to check a certain data already exists in firestore or not
I am working on an app for a hotel, which enables hotel management to report and view concerns and issues. I am using Android and Firebase for this app.
Here is the database structure of a reported concern:
To minimize data download and optimize speed, I am adding "Active" and "Resolved" nodes in the database, like below:
Now, the hotel wants me to add the function to create an Excel report of concerns closed/resolved within the past month. For this, I will be attaching a Single Value Event Listener on the "resolved" node, get keys of resolved concerns, then for each key, fetch data from "allConcerns" node, store each node's data into an ArrayList of String. After which I will use this JSON to Excel API for Android to create Excel file.
I am able to access keys of resolved concerns with this code:
DatabaseReference resolvedReference = FirebaseDatabase.getInstance().getReference()
.child(getApplicationContext().getResources().getString(R.string.concerns))
.child(getApplicationContext().getResources().getString(R.string.resolved));
final ArrayList<String> keys = new ArrayList<>();
resolvedReference.addListenerForSingleValueEvent(new ValueEventListener() {
#Override
public void onDataChange(#NonNull DataSnapshot snapshot) {
//Getting keys of all resolved concerns in keys arraylist here
for (DataSnapshot ds : snapshot.getChildren()){
keys.add(ds.getValue(String.class));
}
//Storing JSON data in this arraylist
final ArrayList<String> data = new ArrayList<>();
for(int i = 0; i<keys.size() ; ++i){
String key = keys.get(i);
//Getting data of each concern here
FirebaseDatabase.getInstance().getReference().child(getApplicationContext().getResources().getString(R.string.allConcerns))
.child(key).addListenerForSingleValueEvent(new ValueEventListener() {
#Override
public void onDataChange(#NonNull DataSnapshot snapshot) {
String type = snapshot.child("type").getValue().toString();
Log.i("Type", type);
if(type.equals("0")) {
SafetyConcernClass s = snapshot.getValue(SafetyConcernClass.class);
Log.i("Snapshot of key", s.toString());
data.add(s.toString());
}
else{
GembaWalkClass g = snapshot.getValue(GembaWalkClass.class);
Log.i("Snapshot of key", g.toString());
data.add(g.toString());
}
Proof proof = snapshot.child("proof").getValue(Proof.class);
Log.i("Proof", proof.toString());
}
#Override
public void onCancelled(#NonNull DatabaseError error) {
}
});
}
//Issue I am facing is here
Log.i("Data size", String.valueOf(data.size()));
}
#Override
public void onCancelled(#NonNull DatabaseError error) {
}
});
}
The real issue here is while logging data.size(). Since Firebase is asynchronous, FOR loop ends before data is fetched and entered into the data ArrayList, hence it gives me a size of 0. And since no data is fetched, I can't create an Excel file.
My question is, how can I make sure I am proceeding to log data.size() ONLY after data of respective resolved concerns is stored in the ArrayList?
The typical approach is to keep a counter or a countdown latch to track how many of the concern snapshots you've already downloaded. Once the counter reaches keys.size() you know that you're done.
Also see Setting Singleton property value in Firebase Listener
You should write your method
addListenerForSingleValueEvent
using AsyncTask or Kotlin coroutines
and in onPostExecute() of AsyncTask, you can proceed to further action.
This question already has an answer here:
getContactsFromFirebase() method return an empty list
(1 answer)
Closed 2 years ago.
Can i get a specific data from firebase database without calling the addValueEventListener. In my code i'm successfully getting the data using firebase database but when i use a function that contains the addValueListener and call the function i can't get the data. Here is my code:
for(CheckOut g: GroceryActivity.list){
String pid = g.getPid();
Log.i("PID", pid);
getOriginalQuantity(pid);
Log.i("Original_Quantity", "" + originalQuantity);}
public void getOriginalQuantity(String pid){
originalQuantityReference = originalQuantityReference.child(pid);
originalQuantityReference.addValueEventListener(new ValueEventListener() {
#Override
public void onDataChange(#NonNull DataSnapshot dataSnapshot) {
Grocery grocery = dataSnapshot.getValue(Grocery.class);
originalQuantity = grocery.getQuantity().toString();
Log.i("Original Quantity", originalQuantity);
}
#Override
public void onCancelled(#NonNull DatabaseError databaseError) {
}
});
}//end getOriginalQuantity method
I'm getting the correct data from the log in the addValueListener where in the the other log i'm getting null valeu
Firebase api is asynchronous meaning that when you use AddValueEventListener to retrieve data from the database, the program will not stop and continue executing. Therefore in this log:
Log.i("Original_Quantity", ""+originalQuantity);
You will get null since it is executed before the data is fully retrieved. There are two ways to access the data either inside the onDataChange or you can do the following:
How to return DataSnapshot value as a result of a method?
No, to get specific data from firebase database you must use addValueEventListener or addListenerForSingleValueEvent
In my project I read data from Firebase and added my data in Arraylist<object>.
I create my Arraylist in oncreate() and used it in onDataChange().
In onDataChange method of addValueEventListener the ArrayList is not null, it's read correctly. But outside it is read 0 (null). Why is that?
My code:
public class MainActivity extends AppCompatActivity {
private ArrayList<myObject> myListOfObjact;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
// Write a message to the database
FirebaseDatabase database = FirebaseDatabase.getInstance();
DatabaseReference myRef = database.getReference();
myListOfObjacts= new ArrayList<myObject>();
Log.e(TAG, " myListOfObjacts.size: " + myListOfObjacts.size());
// size of myListOfObjacts here is 0 (null)
// Read from the database
myRef.addValueEventListener(new ValueEventListener() {
#Override
public void onDataChange(DataSnapshot dataSnapshot) {
for (DataSnapshot postsnapshot : dataSnapshot.getChildren()) {
myObject data1 = postsnapshot.getValue(myObject.class);
myListOfObjacts.add(data1);
}
Log.e(TAG, " myListOfObjacts.size: " + myListOfObjacts.size());
// size of myListOfObjacts here is reading correctly
}
#Override
public void onCancelled(DatabaseError error) {
// Failed to read value
Log.w(TAG, "Failed to read value.", error.toException());
}
});
Log.e(TAG, " myListOfObjacts.size: " + myListOfObjacts.size());
// size of myListOfObjacts here also is 0 (null)
}
}
The Firebase Database client performs all network and disk operations off the main thread.
The Firebase Database client invokes all callbacks to your code on the main thread.
Therefore, onDataChange() is almost always triggered after other main (UI) thread based methods such as onCreate(), onStart()... because onDataChange() relies on your device's internet speed. Actually the null value that you see was null at the time it was first logged or invoked, but not null at the time you see the values populated on your layout.
addValueEventListener() is asynchronous, meaning it returns to the caller immediately, while the Firebase SDK goes and makes the request to the server while your code continues to execute. The callback you pass to it happens some time later, after the request is complete. You don't know how long that's going to be, and you shouldn't make any assumptions about that. Right now, your code is assuming that the results are available immediately after you add the listener, and that's not valid.
If you want the results of a listener, you should only do that from within the listener. You can't expect the results to be available before then.
If you want to know more about why Firebase APIs are asynchronous, read this blog.
I'm trying to create a Property Rental application on Android using Firebase Firestore. Right now, I'm trying to implement a method to delete a specific document (property) within my collection inside Firestore. I figure it is by referencing the auto-generated ID for that particular document, but I simply couldn't get around it.
This is how the delete feature should work:
User clicks on a property item from the RecyclerView
It displays a full profile of that property
User clicks the delete button from the top right corner and deletes the property from the Firestore database
Here is my code where I'm stucked at:
#Override
public boolean onOptionsItemSelected(MenuItem item) {
switch(item.getItemId()){
// The delete button
case R.id.action_delete_btn:
// Do this when user clicks on delete button
Toast.makeText(PropertyProfile.this, "You tried to delete this property", Toast.LENGTH_LONG).show();
deleteItem(item.getOrder());
return super.onOptionsItemSelected(item);
default:
return false;
}
}
// Here's my problem
private void deleteItem(int index) {
firebaseFirestore.collection("Posts")
.document("[DOCUMENT ID RIGHT HERE!]")
.delete()
.addOnSuccessListener(new OnSuccessListener<Void>() {
#Override
public void onSuccess(Void aVoid) {
Toast.makeText(PropertyProfile.this, "You successfully deleted this property", Toast.LENGTH_LONG).show();
}
});
}
In order to use the document id that you are looking for, first you need to store it in a variable. When you are adding a document to the database and you are using a call to document() method without passing an argument, a unique id is generated. To get that id, you should use the following code:
String documentId = postsRef.document().getId();
postsRef.document(documentId).set(yourModelObject);
In which postsRef is the CollectionReference object of your Posts collection and yourModelObject is the object of your Post class. I also recommend you store that id, as a property of your Post document.
Once you have this id, you can use in your refence like this:
firebaseFirestore
.collection("Posts")
.document(documentId)
.delete().addOnSuccessListener(/* ... */);