Fetching data from firebase database - java

I want to fetch data from inside Firebase to check whether this user exists in database but there's a problem that i can't solve , listener trigger late this is my code :-
if I remove while loop i can't fetch object fast
if I keep while loop i enter infinite loop , i don't know why
why listener don't trigger
DataSnapshot fetched ;
public boolean user_exist(final String user) throws Exception {
users.addListenerForSingleValueEvent(new ValueEventListener() {
#Override
public void onDataChange(DataSnapshot dataSnapshot) {
fetched = dataSnapshot ;
}
#Override
public void onCancelled(DatabaseError databaseError) {
}
});
while (fetched == null){
Log.e("dbController","not fetched yet");
}
return fetched.hasChild(user);
}

Firebase has to fetch the data from database and bring it in your app. This may take time, hence it should be done in background. When you add valueEventListener, the fetching is done in background. You may display a progressBar to show data is still loading, and once data is in hands, do the rest of code:
users.child(user).addListenerForSingleValueEvent(new ValueEventListener() {
#Override
public void onDataChange(DataSnapshot dataSnapshot) {
if (dataSnapshot.exists()) {
funUserExists();
} else {
funNoUser();
}
}
#Override
public void onCancelled(DatabaseError databaseError) {
}
});

Related

How to retrieve push() valued data from Firebase to android

I am going to make a simple app and I am completely new to Android development. I want to develop an edit button to save my data in the Realtime Database. This is my code:
holder.edite.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
final DialogPlus dialogPlus=DialogPlus.newDialog(holder.title.getContext())
.setContentHolder(new ViewHolder(R.layout.dialogcontent))
.setExpanded(true,2100)
.create();
View myView=dialogPlus.getHolderView();
EditText title=myView.findViewById(R.id.hTitle);
EditText description=myView.findViewById(R.id.hDescription);
Button submit=myView.findViewById(R.id.usubmit);
title.setText(myItems.getName());
description.setText(myItems.getAddHomeworkDescription());
dialogPlus.show();
submit.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
Map<String,Object> map=new HashMap<>();
map.put("name",title.getText().toString());
map.put("addHomeworkDescription",description.getText().toString());
DatabaseReference myRef = getInstance().getReference().child("Homework");
String uid = FirebaseAuth.getInstance().getCurrentUser().getUid();
// String key = myRef.push().getKey();
myRef.child(uid).child()
.updateChildren(map);
dialogPlus.dismiss();
}
});
}
});
This is how my firebase database looks like
What I want to add into .child() to get highlighted(In the image) Unique id direction. But this unique ID is not always same. It change everythime when user create new one.
You will either have to know the push key (-NN...) value of the node you want to update already, determine it with a query, or loop over all child nodes and update them all.
Update a specific child with a known push key
myRef.child(uid).child("-NNsQO7O9lh0ShefShV")
.updateChildren(map);
Update children matching a specific query
Say that you know you want to update the node with name "test12", you can use a query for that:
myRef.child(uid).orderByChild("name").equalToValue("test12").addListenerForSingleValueEvent(new ValueEventListener() {
#Override
public void onDataChange(DataSnapshot dataSnapshot) {
for (DataSnapshot nodeSnapshot: dataSnapshot.getChildren()) {
nodeSnapshot.getRef().updateChildren(map);
}
}
#Override
public void onCancelled(DatabaseError databaseError) {
throw databaseError.toException();
}
})
Update all children
This is a simpler version of the above, by removing the query condition:
myRef.child(uid).addListenerForSingleValueEvent(new ValueEventListener() {
#Override
public void onDataChange(DataSnapshot dataSnapshot) {
for (DataSnapshot nodeSnapshot: dataSnapshot.getChildren()) {
nodeSnapshot.getRef().updateChildren(map);
}
}
#Override
public void onCancelled(DatabaseError databaseError) {
throw databaseError.toException();
}
})

Firebase not retrieve last data when data changes and not execute conditions inside addValueEventListener in the right way

I'm trying to execute some code in my addValueEventListener based on conditions of values in database, but when data changes, listener execute conditions based on old data, and at the second try listener perform data which I want to use. however data change listener perform listenr(-1) data. To be more clear, if "disable" or "stop" child exist I don't want to execute the code, but after data are updated and these children not existing, conditions when I call AddMessage method not executing again, but it execute method when I call for the second time, it perform correctly till next update of the data where it start again same issue.
sendMessage.setOnClickListener(new View.OnClickListener() {#Override
public void onClick(View v) {
AddMessage();
}
});
private void AddMessage() {
nListener = RootRef.child("List Ref").child(messageReceiverID).child(messageSenderID).addValueEventListener(new ValueEventListener() {
#Override
public void onDataChange(#NonNull DataSnapshot dataSnapshot) {
if (dataSnapshot.exists()) {
if (!dataSnapshot.hasChild("disable") && !dataSnapshot.hasChild("stop")) {
HashMap <String,String> chatMessageMap = new HashMap <>();
chatMessageMap.put("from", messageSenderID);
chatMessageMap.put("type", "check");
chatMessageMap.put("content", messageText);
MessagesRef.child(messageReceiverID).push().setValue(chatMessageMap);
RootRef.child("List Ref").child(messageReceiverID).child(messageSenderID).removeEventListener(nListener);
} else {
RootRef.child("List Ref").child(messageReceiverID).child(messageSenderID).removeEventListener(nListener);
}
}
}
#Override
public void onCancelled(#NonNull DatabaseError databaseError) {
}
});
}
sendMessage.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
String stoppedUser;
myDbref = FirebaseDatabase.getInstance().getReference().child("List Ref").child(<UID_OF_RECEIVER_OF_MESSAGE>);
myDbref.addValueEventListener(new ValueEventListener() {
#Override
public void onDataChange(#NonNull DataSnapshot dataSnapshot) {
try {
stoppedUser = dataSnapshot.child(<UID_OF_SENDER>).child("stop").getValue().toString();
//Now use if-else statement
if(<UID_OF_RECEIVER> == stoppedUser){
Toast.makeText(getApplicationContext(), "You are blocked.", Toast.LENGTH_LONG).show();
} else {
AddMessage();
}
}catch (Throwable e){
Toast.makeText(getApplicationContext(), e.toString(), Toast.LENGTH_SHORT).show();
}
}
#Override
public void onCancelled(#NonNull DatabaseError databaseError) {
}
});
Though you can get <UID_OF_SENDER> by using FirebaseUser currentUserUID = FirebaseAuth.getInstance().getCurrentUser();
Make sure you put the value of <UID_OF_RECEIVER> correctly and also correct the database path if needed.

Firebase datasnapshot data is not saved to variable

I am trying to retrieve data from the firebase realtime database and save it to a variable like this:
mUserDatabase.child(mCurrentUserId).addValueEventListener(new ValueEventListener() {
#Override
public void onDataChange(DataSnapshot dataSnapshot) {
myPublicKeyString = dataSnapshot.child("public_key").getValue().toString();
myPrivateKeyString = dataSnapshot.child("private_key").getValue().toString();
}
#Override
public void onCancelled(DatabaseError databaseError) {
}
});
Where myPublicKeyString and myPrivateKeyString are global variables. When I try to do a System.out.println(myPublicKeyString); inside the ValueEventListener function it does indeed print out the correct data but when I try to do the same outside of the function it prints out null.

How to add a counter in firebase?

So guys, I had the database: Event and User.
When some user has interest in some event clicking the button, this will add a child in eventHasInterest with the user in Event database, and in the database User will add the event that has interest. It's already working, but I need to put a counter to show, how many people has interest, and it's not working, only add once. I need one click, +1, another click -1 on.
btn_interest.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View view) {
databaseEvent.child(getKeyEvent()).addListenerForSingleValueEvent( //get the event by key
new ValueEventListener() {
#Override
public void onDataChange(DataSnapshot dataSnapshot) {
final Event event = dataSnapshot.getValue(Event.class);
user = FirebaseAuth.getInstance().getCurrentUser(); //get the user logged in
if(user != null) {
databaseUser.orderByChild("userEmail").equalTo(user.getEmail()).addValueEventListener(new ValueEventListener() {
#Override
public void onDataChange(DataSnapshot dataSnapshot) {
for (DataSnapshot userSnapshot: dataSnapshot.getChildren()) {
final User user = userSnapshot.getValue(User.class); // user data logged in
databaseUser.orderByChild("userHasInterest").equalTo(event.getEventId()).addValueEventListener(new ValueEventListener() {
#Override
public void onDataChange(DataSnapshot dataSnapshot) {
if (!dataSnapshot.exists()) {
databaseUser.child(user.getUserId()).child("userHasInterest").child(event.getEventId()).setValue(event.getEventId());
databaseEvent.child(event.getEventId()).child("eventAmount").setValue(dataSnapshot.getChildrenCount()+1);
} else {
//event already exists
}
}
#Override
public void onCancelled(DatabaseError databaseError) {
}
});
databaseEvent.orderByChild("eventHasInterest").equalTo(user.getUserId()).addValueEventListener(new ValueEventListener() {
#Override
public void onDataChange(DataSnapshot dataSnapshot) {
if(!dataSnapshot.exists()){
databaseEvent.child(event.getEventId()).child("eventHasInterest").child(user.getUserId()).setValue(user.getUserId());
} else{
//user already exist
}
}
My firebase:
dataSnapshot.getChildrenCount() does not return the int value of eventAmount, it returns the number of children that eventAmount has. In your case, eventAmount will always return 0 since there is no children of eventAmount. I suggest that instead of using getChildrenCount, get the value of the dataSnapshot, and parse that value into an int. After that, increment that value by 1, and store that value instead.
databaseEvent.child(event.getEventId()).child("eventAmount").setValue(Integer.parseInt(dataSnapshot.getValue().toString()) + 1);
EDIT: As suggested by Frank, storing the value using a transaction is recommended to help avoid concurrent updates. I used this post, as well as the post Frank linked to help write the code.
public void updateCount(DatabaseReference database){
database.runTransaction(new Handler() {
#Override
public Result doTransaction(MutableData mutableData) {
//Currently no value in eventAmount
if(mutableData.getValue() == null){
mutableData.setValue(1);
}
else{
mutableData.setValue(Integer.parseInt(mutableData.getValue().toString()) + 1);
}
return Transaction.success(mutableData);
}
#Override
public void onComplete(DatabaseError databaseError, boolean b,
DataSnapshot dataSnapshot) {
//Probably log the error here.
}
});
}
So in your "userHasInterest" onDataChange method, call my method above like this.
#Override
public void onDataChange(DataSnapshot dataSnapshot){
if(!dataSnapshot.exists()) {
databaseUser.child(user.getUserId()).child("userHasInterest").child(event.getEventId()).setValue(event.getEventId());
updateCount(databaseEvent.child(event.getEventId()).child("eventAmount")); //New line here
} else {
//event already exists
}
}

how to make sure Query is not empty

i have an application with many types of users like normalUser,PremiumUser
and in order to define that i use their unique UID in firebasedatabase to each one in their category premium or normal
this is my database firebase shape
--users
-----normal
-----premium
so if user choose normal account he will be assigned to normal only
for me this is how to grab his data later when he log in is as follows
if (auth.getCurrentUser() != null) {
finish();
Query q = FirebaseDatabase.getInstance().getReference().child("users").child("normal").equalTo(auth.getCurrentUser().getUid());
Query q2 = FirebaseDatabase.getInstance().getReference().child("users").child("premium").equalTo(auth.getCurrentUser().getUid());
if (q != null) {
q.addValueEventListener(new ValueEventListener() {
#Override
public void onDataChange(DataSnapshot dataSnapshot) {
startActivity(new Intent(Login.this, Normal.class));
}
#Override
public void onCancelled(DatabaseError databaseError) {
}
});
} else {
q2.addValueEventListener(new ValueEventListener() {
#Override
public void onDataChange(DataSnapshot dataSnapshot) {
startActivity(new Intent(Login.this, Premium.class));
}
#Override
public void onCancelled(DatabaseError databaseError) {
}
});
}
}
but looks like the code enter both activities altough for sure this account exists in one of categories only(normal or premium)
i tried using
if (dataSnapshot.getChildrenCount()>0) //none of both activities is entered
if (dataSnapshot != null)//both Activites still entered
if(dataSnapshot.getValue(Premium.class)!=null)//vvvv
if(dataSnapshot.getValue(Normal.class)!=null)//but still none entered
i also tried
Query q = FirebaseDatabase.getInstance().getReference().child("users").child("normal").equalTo(auth.getCurrentUser().getUid());
final Query q2 = FirebaseDatabase.getInstance().getReference().child("users").child("premium").equalTo(auth.getCurrentUser().getUid());
q.addValueEventListener(new ValueEventListener() {
public void onDataChange(DataSnapshot dataSnapshot) {
if (dataSnapshot.exists()) {
startActivity(new Intent(Login.this, Normal.class));
}
else {
q2.addValueEventListener(new ValueEventListener() {
public void onDataChange(DataSnapshot dataSnapshot) {
if (dataSnapshot.exists()) {
startActivity(new Intent(Login.this, Premium.class));
}
but none of them was entered too
how can i fix that
thanks
Your query will never be null, because you created it just before that. There is no way to know how many results a query has without attaching a listener.
So the closest you can get with your current data structure is to nest the queries:
Query q = FirebaseDatabase.getInstance().getReference().child("users").child("normal").equalTo(auth.getCurrentUser().getUid());
Query q2 = FirebaseDatabase.getInstance().getReference().child("users").child("premium").equalTo(auth.getCurrentUser().getUid());
q.addValueEventListener(new ValueEventListener() {
public void onDataChange(DataSnapshot dataSnapshot) {
if (dataSnapshot.exists()) {
startActivity(new Intent(Login.this, Normal.class));
}
else {
q2.addValueEventListener(new ValueEventListener() {
public void onDataChange(DataSnapshot dataSnapshot) {
startActivity(new Intent(Login.this, Premium.class));
}
public void onCancelled(DatabaseError databaseError) {
throw databaseError.toException();
}
});
}
}
public void onCancelled(DatabaseError databaseError) {
throw databaseError.toException();
}
});
A more direct way to make this work is to change your data structure so that is also contains the payment status for each user. So also store:
user_payment_status
uid1: "normal"
uid2: "premium"
Then you can simply look up the status for the current user with a single value listener. You'll keep your current list around, since you likely also want to show a list of all premium users somewhere in the app.
Duplicating data in this way is quite common in NoSQL databases.
i fixed it by adding to each user a uid then changed
Query q = FirebaseDatabase.getInstance().getReference().child("users").child("normal").equalTo(auth.getCurrentUser().getUid());
Query q2 = FirebaseDatabase.getInstance().getReference().child("users").child("premium").equalTo(auth.getCurrentUser().getUid());
to the following
Query q = FirebaseDatabase.getInstance().getReference().child("users").child("normal").orderByChild("uid").equalTo(auth.getCurrentUser().getUid());
Query q2 = FirebaseDatabase.getInstance().getReference().child("users").child("premium").orderByChild("uid").equalTo(auth.getCurrentUser().getUid());
i still dont know why the first way is wrong

Categories

Resources