Edit specific values in Firebase database using Android Studio - java

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");

Related

Read data then update it and finish by save it

I need you to help me to solve this problem:
The problem is that I want to read a String called coins from the database of Firebase and then turn it into an Integer value. Then when I push a button I want to add 1 to coins and after that, I turn it back into a String value to save it in the database.
So I tried to do this by using onDataChange to read the data and then use
int score = Integer.parseInt(coins) to turn it into an Integer value called score.
After that, I used onClickListener to add 1 to the integer, but Android Studio tells me:
Cannot resolve score
I don't know how to solve this issue so I would be so happy if you could help me with that thing.
This is my code :
public class HomeFragment extends Fragment {
public HomeFragment() {
// Required empty public constructor
}
//firebase
FirebaseAuth firebaseAuth;
FirebaseUser user;
FirebaseDatabase firebaseDatabase;
DatabaseReference databaseReference;
StorageReference storageReference;
//init view
ImageButton addCoinsBtn;
TextView coinsTv;
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
// Inflate the layout for this fragment
View view =inflater.inflate(R.layout.fragment_home, container, false);
//init firebase
firebaseAuth = FirebaseAuth.getInstance();
user = firebaseAuth.getCurrentUser();
firebaseDatabase = FirebaseDatabase.getInstance();
databaseReference = firebaseDatabase.getReference("Users");
storageReference = getInstance().getReference();//firebase storage reference
coinsTv=(TextView)view.findViewById(R.id.coinsTv);
addCoinsBtn=(ImageButton)view.findViewById(R.id.add_coins);
Query query = databaseReference.orderByChild("email").equalTo(user.getEmail());
query.addValueEventListener(new ValueEventListener() {
#Override
public void onDataChange(#NonNull DataSnapshot dataSnapshot) {
//check until required data get
for (DataSnapshot ds : dataSnapshot.getChildren()){
//get data
String coins = ""+ds.child("coins").getValue();
int score = Integer.parseInt(coins);
//set data
coinsTv.setText(score);
}
}
#Override
public void onCancelled(#NonNull DatabaseError databaseError) {
}
});
addCoinsBtn.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
FirebaseDatabase database = FirebaseDatabase.getInstance();
DatabaseReference coins = database.getReference("Users/"+ user.getUid() +"/coins");
Integer score = score + 1;
String scorefinal = Integer.toString(score);
coins.setValue(scorefinal);
}
});
return view;
}
}
Thank you very much for all your bits of help.
This is a basic scoping problem: variables only exist in the scope where you declare them.
So the int score that you declare in onDataChange is not available in the onClick method anymore.
And the Integer score that you declare in onClick is a new variable, which means that Integer score = score + 1; won't work, because the score on the right-hand side doesn't exist/have a value.
The solution is to declare score one level higher, as a member field of your `` class:
Integer score = -1;
Query query = databaseReference.orderByChild("email").equalTo(user.getEmail());
query.addValueEventListener(new ValueEventListener() {
#Override
public void onDataChange(#NonNull DataSnapshot dataSnapshot) {
for (DataSnapshot ds : dataSnapshot.getChildren()){
String coins = ""+ds.child("coins").getValue();
score = Integer.parseInt(coins);
coinsTv.setText(score);
}
}
#Override
public void onCancelled(#NonNull DatabaseError databaseError) {
throw databaseError.toException(); // never ignore errors
}
});
addCoinsBtn.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
FirebaseDatabase database = FirebaseDatabase.getInstance();
DatabaseReference coinsRef = database.getReference("Users/"+ user.getUid() +"/coins");
score = score + 1;
String scorefinal = Integer.toString(score);
coinsRef.setValue(scorefinal);
}
});
I'd highly recommend storing the value as a number in the database, as it saves you constantly converting from string to integer and back. If you do this, the above code becomes:
Integer score = -1;
Query query = databaseReference.orderByChild("email").equalTo(user.getEmail());
query.addValueEventListener(new ValueEventListener() {
#Override
public void onDataChange(#NonNull DataSnapshot dataSnapshot) {
for (DataSnapshot ds : dataSnapshot.getChildren()){
score = ds.child("coins").getValue(Integer.class);
coinsTv.setText(score);
}
}
#Override
public void onCancelled(#NonNull DatabaseError databaseError) {
throw databaseError.toException(); // never ignore errors
}
});
addCoinsBtn.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
FirebaseDatabase database = FirebaseDatabase.getInstance();
DatabaseReference coinsRef = database.getReference("Users/"+ user.getUid() +"/coins");
coinsRef.setValue(score+1);
}
});

To get data of authenticated user failure

public void loadUserInformation() {
final String uid = mAuth.getCurrentUser().getPhoneNumber();
DatabaseReference rootRef = FirebaseDatabase.getInstance().getReference().child("Users");
// DatabaseReference uidRef = rootRef.child("ref").child(uid);
ValueEventListener eventListener = new ValueEventListener() {
#Override
public void onDataChange(DataSnapshot dataSnapshot) {
for(DataSnapshot postSnapshot: dataSnapshot.getChildren()){
String name=postSnapshot.child("Name").getValue().toString();
// String email=postSnapshot.child("Email").getValue().toString();
Name.setText(name);
// Email.setText(email);
}
}
#Override
public void onCancelled(DatabaseError databaseError) {
Toast.makeText(getActivity(),"Error Loading UserDetails",Toast.LENGTH_LONG).show();
}
};
rootRef.addListenerForSingleValueEvent(eventListener);
}
I know why I'm not getting the expected results, its because there's one more child after users. I'm not sure on how to access it, child(uid) gave me a NullPointerException. The present code gives me name of some random user. I want it to return name of the authenticated user i.e. myself
Database - http://ibb.co/iRnF77
Change the phone number to the userid:
FirebaseUser user=FirebaseAuth.getInstance().getCurrentUser();
String userid=user.getUid();
So you will have this database:
Users
userid
Name: namehere
Phone_Number: numberhere
//etc
then you can simply retrieve the data of the current user:
DatabaseReference rootRef = FirebaseDatabase.getInstance().getReference().child("Users").child(userid);
ValueEventListener eventListener = new ValueEventListener() {
#Override
public void onDataChange(DataSnapshot dataSnapshot) {
String name=dataSnapshot.child("Name").getValue().toString();
Name.setText(name);
}
}
#Override
public void onCancelled(DatabaseError databaseError) {
}
};
You don't need the phone number to be the parent node since you already have it as an attribute Phone_Number: number_here, no need to write it twice.
Also getPhoneNumber() can be used if you did phone authentication:
https://firebase.google.com/docs/auth/android/phone-auth

Get specific value from Firebase

I have this firebase database:
That has been created with this code:
private DatabaseReference mDatabase;
private EditText tbfirstname;
private EditText tblastname;
private EditText tbemail;
private Button btnSubmit;
private String str_firstname;
private String str_lastname;
private String str_email;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
mDatabase = FirebaseDatabase.getInstance().getReference().child("Users");
//GUI DECLARATIONS
tbfirstname = (EditText) findViewById(R.id.tb_firstname);
tblastname = (EditText) findViewById(R.id.tb_lastname);
tbemail = (EditText) findViewById(R.id.tb_email);
btnSubmit = (Button) findViewById(R.id.btn_register);
btnSubmit.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View view) {
//HANDLES VALUES FROM TB TO STR
str_firstname = tbfirstname.getText().toString().trim();
str_lastname = tblastname.getText().toString().trim();
str_email = tbemail.getText().toString().trim();
HashMap<String, String> dataMap = new HashMap<String, String>();
dataMap.put("Firstname", str_firstname);
dataMap.put("Lastname", str_lastname);
dataMap.put("Email", str_email);
mDatabase.push().setValue(dataMap).addOnCompleteListener(new OnCompleteListener<Void>() {
#Override
public void onComplete(#NonNull Task<Void> task) {
if(task.isSuccessful()){
Toast.makeText(MainActivity.this,"Registered Successfully!",Toast.LENGTH_LONG).show();
tbfirstname.setText("");
tblastname.setText("");
tbemail.setText("");
} else {
Toast.makeText(MainActivity.this, "There was an Error. Try Again!", Toast.LENGTH_LONG).show();
}
}
});
}
});
}
It's actually a simple app that let users register some data. What I wanna do is I want to create a search textboxthat will locate specific data in the database based on what the user has entered in that textbox and returns a value.
For example I'll search steve#sample.com, if there is an email in the database that has the same value, I want it to return its root value namely L4JyRA77YKldmMWM-C7. If somehow there is no said record, I want it to return with false or something.
Requirements:I'm really a beginner in Android and Firebase so if you could make the code newbie-friendly, that'll really be a great help. Thanks!
first of all you need to fetch all records from firebase database List<User>
create copy of list List<User> temp = new ArrayList();
you can add particular searchable user detail in temp - temp.add(users.get(i));
Now you can get useremail like this email = temp.get(i).getEmailId();
FirebaseDatabase.getInstance().getReference().child("Your table name").orderByChild("email").equalTo(your searchable emailid ).addValueEventListener(new ValueEventListener() {
#Override
public void onDataChange(DataSnapshot dataSnapshot) {
Iterator<DataSnapshot> dataSnapshots = dataSnapshot.getChildren().iterator();
List<User> users = new ArrayList<>();
while (dataSnapshots.hasNext()) {
DataSnapshot dataSnapshotChild = dataSnapshots.next();
User user = dataSnapshotChild.getValue(User.class);
users.add(user);
}
String userids = "";
List<User> temp = new ArrayList();
try {
for (int i = 0; i < users.size(); i++) {
if (users.get(i).getEmailid().equals("your searchable email")) {
temp.add(users.get(i));
//Here you can find your searchable user
Log.e("temp", "+" + temp.get(i).getFirebaseId());
email = temp.get(i).getEmailId();
}
}
} catch (Exception e) {
e.printStackTrace();
Log.e("Logs", e.toString());
}
}
#Override
public void onCancelled(DatabaseError databaseError) {
}
});
DatabaseReference reference = FirebaseDatabase.getInstance().getReference();
Query query = reference.child("Users").orderByChild("Email").equalTo("editext.getText()");
query.addListenerForSingleValueEvent(new ValueEventListener() {
#Override
public void onDataChange(DataSnapshot dataSnapshot) {
if (dataSnapshot.exists()) {
// dataSnapshot is the "issue" node with all children with id 0
for (DataSnapshot issue : dataSnapshot.getChildren()) {
// do something with the individual "issues"
}
}
}
#Override
public void onCancelled(DatabaseError databaseError) {
}
});
Some general things to remember is never name nodes with Capital letters

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);
}

Retrieve all data from Firebase Database

ANDROID: I have a Firebase database like this.
In my app, I would like to compile an arraylist that displays all values from the nameofEntry [DESCRIBED BELOW]. By this I mean the "balso," the "nairboh" and so on.
I have the references:
DatabaseReference root = FirebaseDatabase.getInstance().getReference();
DatabaseReference users = root.child("Users");
DatabaseReference childRef = users.child(userID);
DatabaseReference childRefNameNode = childRef.child(nameOfEntry);
childRefNameNode.child(nameOfEntry).setValue(nameOfEntry);
//FETCH DATA
childRefNameNode.child(nameOfEntry).addValueEventListener(new ValueEventListener() {
#Override
public void onDataChange(DataSnapshot dataSnapshot) {
String valueFromDB = dataSnapshot.getValue(String.class);
Log.i("Jimit", valueFromDB);
}
#Override
public void onCancelled(DatabaseError databaseError) {
}
});
But this only fetches for one entry. How can I get more entries? [All of them]?
You need to use this code snippet. You haven't used any for loop to step over your children.
EDIT: Also, update your database reference as:
//Updated ref
DatabaseReference ref = FirebaseDatabase.getInstance().getReference().child("Users").child(userID);*
//add listener to updated ref
ref.addValueEventListener(new ValueEventListener() {
#Override
public void onDataChange(DataSnapshot dataSnapshot) {
//use the for loop here to step over each child and retrieve data
for (DataSnapshot childSnapshot : dataSnapshot.getChildren()){
String valueFromDB = childSnapshot.getValue(String.class);
Log.i("Jimit", valueFromDB);
}
}
#Override
public void onCancelled(DatabaseError databaseError) {
}
});
Do let me know if it changes anything for you.

Categories

Resources