Java ValueEventListener infinite loop - java

I am having trouble with my Firebase code to add a contact to a user profile. This exact code used to work fine, and now as of today it gets itself into an infinite loop and creates contacts repeatedly until I force kill the application. I can't work out where the loop is, or what may have changed!
Code:
public class AddContacts extends AppCompatActivity {
private EditText addContactNumber;
private Button btnAddContact;
private String userResult, searchPhone, ping_userID;
private FirebaseAuth pingAuth;
DatabaseReference ref;
private FirebaseAuth.AuthStateListener pingAuthListener;
addContactNumber = (EditText) findViewById(R.id.addContactNumber);
btnAddContact = (Button) findViewById(R.id.btnAddContact);
btnAddContact.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
searchPhone = addContactNumber.getText().toString();
ref = FirebaseDatabase.getInstance().getReference().child("Profiles");
ref.orderByChild("Phone").equalTo(searchPhone).addValueEventListener(new ValueEventListener() {
#Override
public void onDataChange(DataSnapshot dataSnapshot) {
for (DataSnapshot datas : dataSnapshot.getChildren()) {
userResult = datas.getKey();
if (userResult != null) {
ping_userID = pingAuth.getCurrentUser().getUid();
DatabaseReference newContact = FirebaseDatabase.getInstance().getReference().child("Profiles").child(ping_userID).child("Contacts");
newContact.setValue(userResult);
DatabaseReference newContactPing = FirebaseDatabase.getInstance().getReference().child("Profiles").child(ping_userID).child("Contacts").child(userResult).child("PingStatus");
newContactPing.setValue(false);
DatabaseReference addRef = FirebaseDatabase.getInstance().getReference().child("Profiles").child(userResult).child("Name");
addRef.addListenerForSingleValueEvent(new ValueEventListener() {
#Override
public void onDataChange(DataSnapshot dataSnapshot) {
String resultName = dataSnapshot.getValue(String.class);
DatabaseReference addContactName = FirebaseDatabase.getInstance().getReference().child("Profiles").child(ping_userID).child("Contacts").child(userResult).child("Name");
addContactName.setValue(resultName);
Toast.makeText(getBaseContext(), "User: " + resultName + " added successfully.", Toast.LENGTH_SHORT).show();
ref.removeEventListener(this);
}
#Override
public void onCancelled(DatabaseError databaseError) {
}
});
} else {
Toast.makeText(getBaseContext(), "User not found.", Toast.LENGTH_SHORT).show();
ref.removeEventListener(this);
break;
}
}
}
#Override
public void onCancelled(DatabaseError databaseError) {
}
});
}
});
}
Also, perhaps as an aside, it never triggers the "User not found" event, even if I enter details that are not in the database.
Any ideas? I am sure it is staring me in the face but I don't see it.
#Peter Haddad Database as requested:
MyAppDatabase
-Profiles
-BCsuC4XAZqVhWj
-Name: "Simon"
-Phone: 123456
-Contacts
-pnYn1NhzzNQAm
-Name: "Bill"
-PingStatus: false
-pnYn1NhzzNQAm
-Name: "Bill"
-Phone: 987654
-Contacts
-BCsuC4XAZqVhWj
-Name: "Simon"
-PingStatus: false

Use addListenerForSingleValueEvent instead of addValueEventListener in both the cases.

Related

Edit specific values in Firebase database using Android Studio

I want to create an "edit user profile" page on Android Studio. The user(which is logged in obviously) can go in and edit user info such as weight and age. Here is how my firebase database is set up:
The database
In this case, a user who is logged in as "Raxor2k", wants to change he`s info such as Age and Weight.
I have made a function that queries the database, and it manages to reach the "AdditionalUserInfo" table which is good. But the next task is to reach those specific values that belong to the logged-in user.
here is the code:
public class UserSettingsActivity extends AppCompatActivity {
private Button mEditInfoButton;
private TextView usernameField;
private EditText ageField, weightField;
private DatabaseReference dbUsernames;
DatabaseReference the_additional_userInfo_table = FirebaseDatabase.getInstance().getReference("AdditionalUserInfo");
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_user_settings);
ageField = (EditText) findViewById(R.id.ageID);
weightField = (EditText) findViewById(R.id.weightID);
mEditInfoButton = (Button) findViewById(R.id.editButton);
usernameField = (TextView) findViewById(R.id.usernameTextViewID);
mEditInfoButton.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
QueryUserInfo();
}
});
}
public void QueryUserInfo(){
FirebaseDatabase database = FirebaseDatabase.getInstance();
DatabaseReference the_additional_userInfo_table = database.getReference("AdditionalUserInfo");
//Query query =the_additional_userInfo_table.child("username");
the_additional_userInfo_table.addListenerForSingleValueEvent(new ValueEventListener() {
#Override
public void onDataChange(DataSnapshot dataSnapshot) {
if (dataSnapshot.exists()) {
Toast.makeText(UserSettingsActivity.this, "User exists!", Toast.LENGTH_SHORT).show();
// dataSnapshot is the "issue" node with all children with id 0
for (DataSnapshot issue : dataSnapshot.getChildren()) {
// do something with the individual "issues"
}
if(!dataSnapshot.exists()){
Toast.makeText(UserSettingsActivity.this, "nooooo user!", Toast.LENGTH_SHORT).show();
}
}
}
#Override
public void onCancelled(DatabaseError databaseError) {
}
});
}
}
To get the data under AdditionalUserInfo that corresponds to a specific user, you need to use a query that looks like this:
DatabaseReference rootRef = FirebaseDatabase.getInstance().getReference();
DatabaseReference additionalUserInfoRef = rootRef.child("AdditionalUserInfo");
Query userQuery = additionalUserInfoRef.orderByChild("username").equalTo("Raxor2k");
ValueEventListener valueEventListener = new ValueEventListener() {
#Override
public void onDataChange(DataSnapshot dataSnapshot) {
for(DataSnapshot ds : dataSnapshot.getChildren()) {
Map<String, Object> map = new HashMap<>();
map.put("user-age", "30");
map.put("user-weight", "30");
ds.getRef().updateChildren(map);
}
}
#Override
public void onCancelled(#NonNull DatabaseError databaseError) {
Log.d(TAG, databaseError.getMessage()); //Don't ignore errors!
}
};
userQuery.addListenerForSingleValueEvent(valueEventListener);
The result in your database will be the change of both properties from 25 to 30. Since you didn't add the database as a text, file I have used in the query he user name but a more elegant way of querying the database would be to use the uid.
Query userQuery = additionalUserInfoRef.orderByChild("user-id").equalTo("IXL ... Eoj");

my values inside onclick() doesn't get displayed until next click

I want to take some values from the database (firebase realtime database) and use it with some calculations or display it in a TextView but when the user clicks the button my application doesn't get the value until the next click with all my methods, with a loop or not. outside of the onClick() method I can get the values just fine.
This is a code for getting data from database and display it in a TextView inside onClick()
DatabaseReference myRef;
private double avgrate;
private String category;
private Button button;
private Spinner categories;
private TextView ratetxt;
protected void onCreate(Bundle savedInstanceState) {
myRef = FirebaseDatabase.getInstance().getReference("user_account");
//initialize
avgrate = 0.0;
button = (Button) findViewById(R.id.button);
ratetxt = (TextView) findViewById(R.id.ratetxt);
ratetxt.setVisibility(View.GONE);
// for category adapter -- it works
myRef.child("(username)").child("category").addListenerForSingleValueEvent(new ValueEventListener() {
#Override
public void onDataChange(DataSnapshot dataSnapshot) {
final List<String> propertyAddressList = new ArrayList<String>();
for (DataSnapshot ds : dataSnapshot.getChildren()) {
String propertyAddress = ds.getKey();
if (propertyAddress != null) {
propertyAddressList.add(propertyAddress);
for (DataSnapshot ds2 : dataSnapshot.child(propertyAddress).getChildren()) {
String sub = (String) ds2.getValue();
if (sub != null && !sub.contains("null")) {
propertyAddressList.add(sub);
}
}
}
}
categories = (Spinner) findViewById(R.id.categ);
ArrayAdapter<String> addressAdapter = new ArrayAdapter<String>(myactivity.this, android.R.layout.simple_spinner_item, propertyAddressList);
addressAdapter.setDropDownViewResource(android.R.layout.simple_spinner_dropdown_item);
categories.setAdapter(addressAdapter);
}
#Override
public void onCancelled(DatabaseError databaseError) {
Toast.makeText(getApplicationContext(), "ERROR", Toast.LENGTH_SHORT).show();
}
});
// ON CLICK
button.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
category = categories.getSelectedItem().toString();
if (category.isEmpty()) {
Toast.makeText(getApplicationContext(), "ERROR - CHOOSE CATEGORY", Toast.LENGTH_SHORT).show();
} else {
// take average rating -- HERE IS THE PROBLEM
myRef.child("(username)").child("rating").child(category).addListenerForSingleValueEvent(new ValueEventListener() {
#Override
public void onDataChange(DataSnapshot dataSnapshot) {
for (DataSnapshot ds : dataSnapshot.getChildren()) {
String str = (String) dataSnapshot.child("avg").getValue(String.class);
if (str != null) {
avgrate = Double.parseDouble(str);
}
}
}
#Override
public void onCancelled(DatabaseError databaseError) {
Toast.makeText(getApplicationContext(), "ERROR", Toast.LENGTH_SHORT).show();
}
});
ratetxt.setVisibility(View.VISIBLE);
ratetxt.setText("AVG. RATE: "+avgrate+"");
}/*close else*/ }});// End of OnClick()
} // END OF OnCreate()
here is a code where I have to take the average rating for a chosen category, and set it in a text view, the first time I press the button the avg. will be 0.0 next time it will set the real value, if I don't initialize it, it will set null at first then the real value, I don't know how to fix it
Add these lines inside onDataChange() in button.setOnClickListener ()
Instead of writing outside the onDataChange ()
ratetxt.setVisibility(View.VISIBLE);
ratetxt.setText("AVG. RATE: "+avgrate+"");
Below are codes after making changes. Hope this help.
myRef.child("(username)").child("rating").child(category).addListenerForSingleValueEvent(new ValueEventListener() {
#Override
public void onDataChange(DataSnapshot dataSnapshot) {
for (DataSnapshot ds : dataSnapshot.getChildren()) {
String str = (String) dataSnapshot.child("avg").getValue(String.class);
if (str != null) {
avgrate = Double.parseDouble(str);
ratetxt.setVisibility(View.VISIBLE);
ratetxt.setText("AVG. RATE: "+avgrate+"");
}
}
}
#Override
public void onCancelled(DatabaseError databaseError) {
Toast.makeText(getApplicationContext(), "ERROR", Toast.LENGTH_SHORT).show();
}
});

How to create a condition if there is the same value in firebase

How can I see if there is an equal value in a child and not save if it exists.
I tried doing this here but it did not work:
How can I check if a value exists already in a Firebase data class Android
FirebaseAuth autenticacao = ConfiguracaoFirebase.getFirebaseAutenticacao();
final String idUsuario = CustomBase64.codificarBase64(autenticacao.getCurrentUser().getEmail());
DatabaseReference firebase = ConfiguracaoFirebase.getFirebaseDatabase().child("historico").child(idUsuario);
firebase.addListenerForSingleValueEvent(new ValueEventListener() {
#Override
public void onDataChange(DataSnapshot dataSnapshot) {
if (dataSnapshot.hasChild("id")) {
Toast.makeText(getActivity(), "Exist", Toast.LENGTH_LONG).show();
} else {
Toast.makeText(getActivity(), "No Exist", Toast.LENGTH_LONG).show();
}
}
#Override
public void onCancelled(DatabaseError databaseError) {
}
});
Create yourself another function that pushes the data to firebase and call it from inside your listener. (in this example, create the function pushValueToFirebase)
FirebaseAuth autenticacao = ConfiguracaoFirebase.getFirebaseAutenticacao();
final String idUsuario = CustomBase64.codificarBase64(autenticacao.getCurrentUser().getEmail());
DatabaseReference firebase = ConfiguracaoFirebase.getFirebaseDatabase().child("historico");
firebase.addListenerForSingleValueEvent(new ValueEventListener() {
#Override
public void onDataChange(DataSnapshot dataSnapshot) {
Boolean exists = false;
for (DataSnapshot child : dataSnapshot.getChildren()) {
if (child.getKey().equals(idUsario) {
exists = true;
}
}
if (!exists) {
//Your code here to push idUsario
}
}
#Override
public void onCancelled(DatabaseError databaseError) {
}
});
Try this:
FirebaseAuth autenticacao = ConfiguracaoFirebase.getFirebaseAutenticacao();
final String idUsuario = CustomBase64.codificarBase64(autenticacao.getCurrentUser().getEmail());
DatabaseReference firebase = ConfiguracaoFirebase.getFirebaseDatabase().child("historico").child(idUsuario).child("id");
firebase.addListenerForSingleValueEvent(new ValueEventListener() {
#Override
public void onDataChange(DataSnapshot dataSnapshot) {
if (dataSnapshot.exists()) {
Toast.makeText(getActivity(), "Exist", Toast.LENGTH_LONG).show();
} else {
Toast.makeText(getActivity(), "No Exist", Toast.LENGTH_LONG).show();
}
}
#Override
public void onCancelled(DatabaseError databaseError) {
}
});
Add the child id to the reference above child("historico").child(idUsuario).child("id") then use exists() to check if this dataSnapshot is in your database.

how get value from Firebase

I am new in android and I want to get userIDS from Firebase Database, I've tried by using this but it returns null.
By using this code
Value of Constants.ARG_CHAT_GROUP_ROOMS=Groups and Constants.NEW_NODE=newGroup
private void getMYuid() {
String senderUid = FirebaseAuth.getInstance().getCurrentUser().getUid();
DatabaseReference mTest = FirebaseDatabase.getInstance().getReference();
mTest.child(Constants.ARG_CHAT_GROUP_ROOMS).child(Constants.NEW_NODE)
.child(senderUid).addListenerForSingleValueEvent(new ValueEventListener() {
#Override
public void onDataChange(DataSnapshot dataSnapshot) {
if (!dataSnapshot.exists()){
Toast.makeText(ActivityChatView.this, "not exist", Toast.LENGTH_SHORT).show();
Log.e("151","ACV"+dataSnapshot);
}
}
#Override
public void onCancelled(DatabaseError databaseError) {
}
});
Log.e("139","ACV"+senderUid);
}
Database Structure is this
if you want the first one under 15052169227329_myGroupName_Hell By Anne: Your problem is that you forgot the node before "Constants.NEW_NODE"
private void getMYuid() {
String senderUid = FirebaseAuth.getInstance().getCurrentUser().getUid();
DatabaseReference mTest = FirebaseDatabase.getInstance().getReference();
mTest.child(Constants.ARG_CHAT_GROUP_ROOMS).child("15052169227329_myGroupName_Hell By Anne").child(Constants.NEW_NODE)
.addListenerForSingleValueEvent(new ValueEventListener() {
#Override
public void onDataChange(DataSnapshot dataSnapshot) {
if (!dataSnapshot.exists()){
Toast.makeText(ActivityChatView.this, "not exist", Toast.LENGTH_SHORT).show();
Log.e("151","ACV"+dataSnapshot);
}
// You can cast this object later but it seems that that is a string and not an array
Object yourRequiredObject = dataSnapshot.child("usersIDS").getValue();
}
#Override
public void onCancelled(DatabaseError databaseError) {
}
});
Log.e("139","ACV"+senderUid);
}
As i see, it's not an array it's a String. To get the userIDS, please use the following code:
DatabaseReference rootRef = FirebaseDatabase.getInstance().getReference();
DatabaseReference yourRef = rootRef.child(Constants.ARG_CHAT_GROUP_ROOMS).child(senderUid).child(Constants.NEW_NODE);
ValueEventListener eventListener = new ValueEventListener() {
#Override
public void onDataChange(DataSnapshot dataSnapshot) {
String usersIDS = dataSnapshot.child("usersIDS").getValue(String.class);
Log.d("TAG", usersIDS);
//Here you can split the usersIDS String by , (comma)
}
#Override
public void onCancelled(DatabaseError databaseError) {}
};
yourRef.addListenerForSingleValueEvent(eventListener);
In which senderUid is the missing child. This child can have the value like 1505217176288_myGroupName_1 or other coresponding group names.

Changing variable within Event Listener?

I am developing an android recipe app, User's have the option to only view vegan recipes. I am using Firebase as my Database where I am storing a variable "vegan", in my activity which displays the recipes I am retrieving the value of "vegan" from my database, which can be either "yes" or "no" (line: 54) and then the if statement (line: 65) checks if the user want's vegan recipes or not, however vegan = user.Vegan; does not seem to be changing the variable vegan, I know I am getting the value from the database but it won't change the value of vegan, can anyone tell me where I'm going wrong?
public class SwipeActivity extends AppCompatActivity implements View.OnClickListener {
private static final String TAG = "MainActivity";
private DatabaseReference mRecipeReference;
private DatabaseReference newRef;
private DatabaseReference myRef3;
private DatabaseReference veganRef;
private TextView editTextName;
private TextView editTextCategory;
private ImageView profileImageView;
private ImageButton Back;
private ImageButton Like;
private ImageButton Dislike;
private DatabaseReference databaseReference;
private DatabaseReference userRef;
String imgURL;
String recipeKey;
Map<String, Recipe> likedRecipes = new HashMap<String,Recipe>();
String user = FirebaseAuth.getInstance().getCurrentUser().getUid();
String vegan = "no"; //Here is the variable declaration
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_swipe);
databaseReference = FirebaseDatabase.getInstance().getReference();
userRef = FirebaseDatabase.getInstance().getReference().child("user").child(user);
mRecipeReference = FirebaseDatabase.getInstance().getReference().child("recipe");
editTextName = (TextView) findViewById(R.id.editTextName);
editTextCategory = (TextView) findViewById(R.id.editTextCategory);
profileImageView = (ImageView) findViewById(R.id.profileImageView);
Back = (ImageButton) findViewById(R.id.Back);
Back.setOnClickListener(this);
Like = (ImageButton) findViewById(R.id.Like);
Like.setOnClickListener(this);
Dislike = (ImageButton) findViewById(R.id.Dislike);
Dislike.setOnClickListener(this);
}
#Override
public void onStart() {
super.onStart();
ValueEventListener userListener = new ValueEventListener() {
#Override
public void onDataChange(DataSnapshot dataSnapshot) {
User user = dataSnapshot.getValue(User.class);
vegan = user.Vegan; //Here I am retrieving the string from firebase database, which is either "yes" or "no"
}
#Override
public void onCancelled(DatabaseError databaseError) {
Log.w(TAG, "loadPost:onCancelled", databaseError.toException());
// ...
}
};
userRef.addValueEventListener(userListener);
if (vegan == "yes") { //Here I am checking if the user is vegan or not
veganRef = databaseReference.child("recipe");
veganRef.orderByChild("Category").equalTo("Vegan").addValueEventListener(new ValueEventListener() {
#Override
public void onDataChange(DataSnapshot dataSnapshot) {
for (DataSnapshot recipeSnapshot : dataSnapshot.getChildren()) {
Recipe recipe = recipeSnapshot.getValue(Recipe.class);
recipeKey = recipeSnapshot.getKey();
editTextName.setText(recipe.Name + ", " + recipe.Calories);
editTextCategory.setText(recipe.Category);
imgURL = recipe.Img;
Picasso.with(getApplicationContext()).load(imgURL)//download URL
.placeholder(R.drawable.placeholder_image)//use default image
.error(R.drawable.placeholder_image)//if failed
.into(profileImageView);//imageview
likedRecipes.put(recipeKey, recipe);
}
}
#Override
public void onCancelled(DatabaseError databaseError) {
Log.w(TAG, "loadPost:onCancelled", databaseError.toException());
}
});
}
}
}
The problem is more than likely that onDataChange hasn't been called by time you check vegan in that if statement. Callbacks like that are asynchronous so you will need to wait for callback before performing any logic that's dependent on result.
In general what you're running in to is something many people moving to Firebase from SQL background encounter when trying to map over "joins" like this to the nested queries that Firebase requires. Probably outside scope of this particular question but use of RxJava makes managing set of operations like this much easier (for example that have async responses and 2nd query needs to use response of first one).
In your onStart() do something like this
#Override
public void onStart() {
super.onStart();
ValueEventListener userListener = new ValueEventListener() {
#Override
public void onDataChange(DataSnapshot dataSnapshot) {
User user = dataSnapshot.getValue(User.class);
vegan = user.Vegan;
if (vegan == "yes") { //Here I am checking if the user is vegan or not
veganRef = databaseReference.child("recipe");
veganRef.orderByChild("Category").equalTo("Vegan").addValueEventListener(new ValueEventListener() {
#Override
public void onDataChange(DataSnapshot dataSnapshot) {
for (DataSnapshot recipeSnapshot : dataSnapshot.getChildren()) {
Recipe recipe = recipeSnapshot.getValue(Recipe.class);
recipeKey = recipeSnapshot.getKey();
editTextName.setText(recipe.Name + ", " + recipe.Calories);
editTextCategory.setText(recipe.Category);
imgURL = recipe.Img;
Picasso.with(getApplicationContext()).load(imgURL)//download URL
.placeholder(R.drawable.placeholder_image)//use default image
.error(R.drawable.placeholder_image)//if failed
.into(profileImageView);//imageview
likedRecipes.put(recipeKey, recipe);
}
}
#Override
public void onCancelled(DatabaseError databaseError) {
Log.w(TAG, "loadPost:onCancelled", databaseError.toException());
}
});
}
}
#Override
public void onCancelled(DatabaseError databaseError) {
Log.w(TAG, "loadPost:onCancelled", databaseError.toException());
// ...
}
};
userRef.addValueEventListener(userListener);
}

Categories

Resources