i was trying to update only one field when user clicks a button
here is the database
i need to update report_status when user clicks a button
b1.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
report_value=Integer.parseInt(arrayforreport.get(posi));
report_value++;
databaseReference.addValueEventListener(new ValueEventListener() {
#Override
public void onDataChange(DataSnapshot dataSnapshot) {
//i need to update report_status by id
}
#Override
public void onCancelled(DatabaseError databaseError) {
}
});
}
});
In order to update a value in your Firebase database there is no need to attach a listener, that is needed only when you need to read data. So to update a particular node, you only need to use setValue() method directly on the databaseReference object.
So assuming that the type node is a direct child of your Firebase database, please use the following line of code:
DatabaseReference rootRef = FirebaseDatabase.getInstance().getReference();
rootRef.child("type")
.child("Whatsapp")
.child("Shopping Deals")
.child(shoppingDealId)
.child("report_status")
.setValue("newValue");
In which shoppingDealId is the id of a particular shopping deal. You can get this id using the following line of code:
String key = ref.push().getKey();
addValueEventListener is to retrieve the value, you don't need it to set the value.
First get the key from DatabaseReference then use setValue to change the value.
b1.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
report_value=Integer.parseInt(arrayforreport.get(posi));
report_value++;
DatabaseReference databaseReference = adapter.getRef(position);
String key = databaseReference.getKey();
databaseReference.child("type").child("Whatsapp").child("Shopping Deals").child(key).child("report_status").setValue(report_status);
}
});
Related
I'm working on a Firebase ecommerce app, I have been trying to update the password when passing the email of the user in "forgot password" feature but i can't get it right.
Here is my Firebase structure:
I want the method to get the user with the entered email, then update his password to a new one.
Here is my code:
set_new_pass.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View view) {
DatabaseReference reference = FirebaseDatabase.getInstance().getReference("users");
Query checkUserDatabase = reference.orderByChild("email").equalTo(user_email);
String user_newpass=new_password.getText().toString();
HashMap hashMap = new HashMap();
hashMap.put("password",user_newpass);
// hashMap.put("email",user_email);
checkUserDatabase.addListenerForSingleValueEvent(new ValueEventListener() {
#Override
public void onDataChange(#NonNull DataSnapshot snapshot) {
if (snapshot.exists()){
//String username_ofuser =hashMap.get("username").toString();
reference.child(user_username).updateChildren(hashMap).addOnSuccessListener(new OnSuccessListener() {
#Override
public void onSuccess(Object o) {
Toast.makeText(SetNewPassword.this, "your password is successfully changed!", Toast.LENGTH_SHORT).show();
}
});
}
}
How can I achieve my results?
this code should change the password of the user that has his email entered but it doesn't change anything actually so what can i do to make it work correctly??
I'm quite confused with listeners and Firebase. I understand that the only way to retrieve data from Firebase is listeners. I'm using addListenerForSingleValueEvent to retrieve the username value, which it works well only when that value changes or when I execute this code for a second time. Username value shouldn't change at all but I still need to read it often. How do you read from FB when no changes had occurred?
FirebaseAuth mAuth = FirebaseAuth.getInstance();
FirebaseUser user = mAuth.getCurrentUser();
FirebaseDatabase database = FirebaseDatabase.getInstance();
DatabaseReference myRef = database.getReference("forum")
.child("level1exercice1").child("post").child("username");
myRef.addListenerForSingleValueEvent(new ValueEventListener() {
#Override
public void onDataChange(#NonNull DataSnapshot snapshot) {
value = snapshot.getValue(String.class);
}
#Override
public void onCancelled(#NonNull DatabaseError error) {
}
});
Have you tried reading it as a snapshot and then storing it as a cookie for future use?
The following code is from Firebase Docs:
FirebaseDatabase.DefaultInstance
.GetReference("Leaders").OrderByChild("score").LimitToLast(1)
.ValueChanged += HandleValueChanged;
}
void HandleValueChanged(object sender, ValueChangedEventArgs args) {
if (args.DatabaseError != null) {
Debug.LogError(args.DatabaseError.Message);
return;
} // Do something with the data in args.Snapshot
}
My Firebase Realtime Database has been built by loading an object of the Java class HashMap. In my Android Studio app I'm trying to write a method that takes a String (the key) as input, searches through the database and if the string is found it returns the associated Float (the value), otherwise it returns 0. How can I do this? Any help would be really appreciated!
EDIT: I've tried to follow the suggestions, adapting them to my particular case, but I didn't manage to solve the problem yet.
I wrote the following code in MainActivity:
DatabaseReference myRef;
Float tempValue;
#Override
protected void onCreate(Bundle savedInstanceState) {
...
myRef = FirebaseDatabase.getInstance().getReference("myRoot");
tempValue=0f;
...
}
public void retrieveValueFromDatabase(String childName, final MainActivity activity){
myRef.child(childName).addListenerForSingleValueEvent(new ValueEventListener() {
#Override
public void onDataChange(DataSnapshot dataSnapshot) {
Float value=dataSnapshot.getValue(Float.class);
if (value==null){
value=0f;
}
activity.tempValue=value;
//First Toast
//Toast.makeText(activity,"tempValue = "+tempValue.toString(), Toast.LENGTH_LONG).show();
}
#Override
public void onCancelled(DatabaseError databaseError) {
throw databaseError.toException();
}
});
}
public void useValues(){
retrieveValueFromDatabase(childName,this);
//Second Toast
//Toast.makeText(this,"tempValue = "+tempValue.toString(), Toast.LENGTH_LONG).show();
//code using tempValue from here
...
}
If I uncomment the first toast, the correct value inside tempValue is shown, but if I uncomment the second toast, the value of tempValue shown is the default one (0.0). What am I missing?
You need to use addValueEventListener to retrieve data from the database:
DatabaseReference ref = FirebaseDatabase.getInstance().getReference("myRoot").orderByChild("name").equalTo("peter");
ref.addValueEventListener(new ValueEventListener() {
#Override
public void onDataChange(DataSnapshot dataSnapshot) {
Log.i("Database", dataSnapshot.child("floatValue").getValue(Long.class));
}
#Override
public void onCancelled(DatabaseError databaseError) {
throw databaseError.toException();
}
})
Here, you add a reference to the root node, then query using equalTo() to check if name = peter exists in the database and return the float value.
You should read the guide:
https://firebase.google.com/docs/database/android/read-and-write
Can anyone teach me how to update my Firebase value when I click on my Android Studio App? There is no need to retrieve and display the data. Just an incremental value in my Realtime Database. For example, the Firebase counter value is 0 now, how I can increase the counter value in Firebase when I click on a button? I have tried using the code below, but it is not working.
import com.firebase.client.Firebase;
public class Voting extends AppCompatActivity {
private Button msendData;
int counter;
private Firebase mRef;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_voting);
Firebase.setAndroidContext(this);
mRef = new Firebase("https://lollol.firebaseio.com/");
msendData = (Button) findViewById(R.id.votethis);
msendData.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View view) {
Firebase mRefChild = mRef.child("Booth A");
mRefChild.setValue(counter++);
}
Edit: 20222608
Actually, there is a really simple solution nowadays in which we can increment a field in the Realtime Database which is:
scoreRef.setValue(ServerValue.increment(1));
And to decrement a value, simply pass a negative number:
scoreRef.setValue(ServerValue.increment(-1));
In order to increment a value in a Firebase database, first of all, you need to retrieve that value. There is no way to increment a value without knowing it. To achieve this, I definitely recommend you to use Firebase Transaction.
Let's take an example. Let's assume we want to increment a counter. In order to achieve this, please use the following code to set the default value of the counter.
DatabaseReference rootRef = FirebaseDatabase.getInstance().getReference();
rootRef.child("score").setValue(1);
Assuming that the score field is of type Integer, to use transactions, please use the following method:
public static void setScore(String operation) {
DatabaseReference rootRef = FirebaseDatabase.getInstance().getReference();
DatabaseReference scoreRef = rootRef.child("score");
scoreRef.runTransaction(new Transaction.Handler() {
#Override
public Transaction.Result doTransaction(MutableData mutableData) {
Integer score = mutableData.getValue(Integer.class);
if (score == null) {
return Transaction.success(mutableData);
}
if (operation.equals("increaseScore")) {
mutableData.setValue(score + 1);
} else if (operation.equals("decreaseScore")){
mutableData.setValue(score - 1);
}
return Transaction.success(mutableData);
}
#Override
public void onComplete(DatabaseError databaseError, boolean b, DataSnapshot dataSnapshot) {}
});
}
Using transactions, you will avoid inconsistent results if users are trying to increase/decrease the score at the same time. So as a conclusion, call this method accordingly to your increase/decrease operation.
If you want to read the score, please use the following code:
DatabaseReference rootRef = FirebaseDatabase.getInstance().getReference();
DatabaseReference scoreRef = rootRef.child("score");
ValueEventListener eventListener = new ValueEventListener() {
#Override
public void onDataChange(DataSnapshot dataSnapshot) {
Integer score = dataSnapshot.getValue(Integer.class);
Log.d("TAG", "score: " + score);
}
#Override
public void onCancelled(DatabaseError databaseError) {}
};
scoreRef.addListenerForSingleValueEvent(eventListener);
Get the value from the database.
Make a simple while loop, with the number of increments you need. Declare the variable globally, not within the onCreate methods.
Set them back to the Database.
You don't need to retrieve the value if you use ServerValue.increment(). Recently, It landed on Flutter in version firebase_database 4.1.
The way you can use is:
mRefChild.set(ServerValue.increment(1));
I use Firebase to handle the Auth topic of my Android app.
I also save a user profile on Firebase, that contain user id and extra options that user can update in the android app.
At startup, the app check the auth, and auth. It reload the user profile (on Firebase) to then update my userInstance on the app.
Firebase is set as offline capable at app level.
The userInstance POJO is sync with Firebase at log and stop to be sync at unlog.
I have a special parameter, in my user profile that I can change (as an admin).
Every-time I update it on the Firebase console, it is replaced by the previous value when the app start again.
How can this happen ?
BTW :
1/ Based on which mechanism are the data merged, if multiple client have different local values ?
Here is simpler code, where I tried to reproduce the error. :
MyApplication.java
public class MyApplication extends Application {
#Override
public void onCreate() {
super.onCreate();
Firebase.setAndroidContext(this);
Firebase.getDefaultConfig().setLogLevel(Logger.Level.DEBUG);
Firebase.getDefaultConfig().setPersistenceEnabled(true);
}
}
MainActivity
public class MainActivity extends AppCompatActivity {
Firebase ref;
User user;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
ref = new Firebase("https://millezim-test.firebaseIO.com").child("user");
ref.keepSynced(true);
Button br = (Button) findViewById(R.id.b_read);
Button bs = (Button) findViewById(R.id.b_save);
final TextView tv_r = (TextView) findViewById(R.id.tv_value_toread);
final EditText tv_s = (EditText) findViewById(R.id.tv_value_tosave);
user = new User();
bs.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
if (!tv_s.getText().toString().equalsIgnoreCase(""))
user.setAge(Integer.valueOf(tv_s.getText().toString()));
ref.setValue(user);
}
});
br.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
ref.addListenerForSingleValueEvent(new ValueEventListener() {
#Override
public void onDataChange(DataSnapshot dataSnapshot) {
User u = dataSnapshot.getValue(User.class);
if (u != null)
tv_r.setText(String.valueOf(u.getAge()));
else
tv_r.setText("Bad Value");
}
#Override
public void onCancelled(FirebaseError firebaseError) {
}
});
}
});
ref.addValueEventListener(new ValueEventListener() {
#Override
public void onDataChange(DataSnapshot dataSnapshot) {
User u = dataSnapshot.getValue(User.class);
u.setCounter(u.getCounter() + 1);
user = u;
saveUser();
}
#Override
public void onCancelled(FirebaseError firebaseError) {
}
});
}
public void saveUser() {
ref.setValue(user);
}
}
If you just change a value in the app, then the counter inc until the app stop : this is normal. But what is strand is the age pass from old to new then to old cyclically without stopping.
And I feel that behavior in my app, without the cyclic, as I do not have a counter, but I cannot change a parameter in the admin client, I always get back the previous value stored in the mobile.
I just Auth, then I update my UserInstance with AuthData + the User fetch from Firebase (probably the cached data), and then I save back the updated User under Firebase (As I may got new AuthData, and I normally get the latest User from Firebase)
2/ In this simple example, I saw that if I read the value at start, it fetch the data cached in the app. How can I force having online data ?
The problem comes from the fact that you're using disk persistence with a single-value event listener. When you do:
ref.addListenerForSingleValueEvent(new ValueEventListener() {...
You're asking for a single value of that location (the user in your case). If Firebase has a value for that location in its local cache, it will fire for that value straight away.
The best way to solve this is to not use a single-value listener, but instead use a regular event listener. That way you will get two events: one for the cached version and one for the version that comes back from the server (if it is different).
The only alternative is to not use Firebase's disk persistence. Without that, there won't be a local cache for the data to be read from upon a restart.
There were a few discussions about this combination on the Firebase mailing list. Here's one: https://groups.google.com/forum/#!msg/firebase-talk/ptTtEyBDKls/XbNKD_K8CQAJ
After digesting a bit, my current strategy is to use Firebase for my data persistance, and not use anymore my own objects. (Before I had to sync UI, my data, the firebase cache, and the server data)
So now, I use
use disk caching
use onValueEventListener
keep update data (only to be read with component that need sync data)
trigger event that update UI (for component that can accept async data)
define some specific setter, that update data on Firebase (not anymore at app level)
It does means, that when I update a data, it goes to the server (or Firebase caching layer) until it goes back to the UI. As firebase handle this caching, if fast this is fast enough, and this is Firebase that deal with network sync.
To bring the (1) solution from #frank-van-puffelen into code :
public class MainActivity extends AppCompatActivity {
Firebase ref;
User user;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
ref = new Firebase("https://test.firebaseIO.com").child("user");
ref.keepSynced(true);
Button br = (Button) findViewById(R.id.b_read);
Button bs = (Button) findViewById(R.id.b_save);
final TextView tv_r = (TextView) findViewById(R.id.tv_value_toread);
final EditText tv_s = (EditText) findViewById(R.id.tv_value_tosave);
user = new User();
bs.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
if (!tv_s.getText().toString().equalsIgnoreCase(""))
user.setAge(Integer.valueOf(tv_s.getText().toString()));
ref.setValue(user);
}
});
br.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
ref.addValueEventListener(new ValueEventListener() {
#Override
public void onDataChange(DataSnapshot dataSnapshot) {
User u = dataSnapshot.getValue(User.class);
if (u != null)
tv_r.setText(String.valueOf(u.getAge()));
else
tv_r.setText("Bad Value");
}
#Override
public void onCancelled(FirebaseError firebaseError) {
}
});
}
});
ref.addValueEventListener(new ValueEventListener() {
#Override
public void onDataChange(DataSnapshot dataSnapshot) {
User u = dataSnapshot.getValue(User.class);
u.setCounter(u.getCounter() + 1);
user = u;
saveUser();
}
#Override
public void onCancelled(FirebaseError firebaseError) {
}
});
}
public void saveUser() {
ref.setValue(user);
}
}
However, this change nothing, even worst. Now it seems that every value set, stay as a ghost value (hold by client/server request), and the value toggling can be seen with every values set !
EDIT
The following code worked out !
Having a normal ValueListener, that you stopped before saving again a value, and you enable back when save is completed ! (Ok I was thinking this may be done in the Firebase Framework).
public class MainActivity extends AppCompatActivity {
Firebase ref;
User user;
private ValueEventListener theListener;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
ref = new Firebase("https://test.firebaseIO.com").child("user");
ref.keepSynced(false);
Button bs = (Button) findViewById(R.id.b_save);
final EditText tv_s = (EditText) findViewById(R.id.tv_value_tosave);
user = new User();
bs.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
if (!tv_s.getText().toString().equalsIgnoreCase(""))
user.setAge(Integer.valueOf(tv_s.getText().toString()));
ref.setValue(user);
}
});
theListener = new ValueEventListener() {
#Override
public void onDataChange(DataSnapshot dataSnapshot) {
User u = dataSnapshot.getValue(User.class);
u.setCounter(u.getCounter() + 1);
user = u;
updateUI(u);
saveUser();
}
#Override
public void onCancelled(FirebaseError firebaseError) {
}
};
ref.addValueEventListener(theListener);
}
public void saveUser() {
ref.removeEventListener(theListener);
ref.setValue(user, new Firebase.CompletionListener() {
#Override
public void onComplete(FirebaseError firebaseError, Firebase firebase) {
ref.addValueEventListener(theListener);
}
});
}
public void updateUI(User user) {
TextView tv_r = (TextView) findViewById(R.id.tv_value_toread);
if (user != null)
tv_r.setText(String.valueOf(user.getAge()));
else
tv_r.setText("Bad Value");
}
}
EDIT
However this do not allow to change a value on the admin page. The age value is set and then remain back to the one that is save on the mobile.
So I imaging then the only solution is to solve at system level. DO NOT USE VALUELISTENER FOR VALUE THAT AN APP CAN SAVE AND THAT CAN BE SAVED BY THIRD PARTY APP. Please advise/correct this assumption !