So I have a simple ecommerce app that has products(custom objects) on the cart and a proceed to checkout button. When the button is pressed I send an ArrayList with product ids with the intent so I can access them when confirming the order.
Now I need to loop through this list and make a separate order for each item on firebase(because there a are multiple venders involved). But when I do this it keeps duplicating the list of items on my home screen when it opens it as though its an infinite loop that keeps calling the home screen intent.
So here is the ConfirmOrderActivity confirmOrder code
private void confirmOrder() {
loadingBar.show();
String locationJson = null;
if (useCurrentLocation.isChecked()){
Gson gson = new Gson();
locationJson = gson.toJson(location);
}
final String saveCurrentDate, saveCurrentTime;
Calendar callForDate = Calendar.getInstance();
SimpleDateFormat currentDate = new SimpleDateFormat("MMM dd, yyyy");
saveCurrentDate = currentDate.format(callForDate.getTime());
SimpleDateFormat currentTime = new SimpleDateFormat("HH:mm:ss a");
saveCurrentTime = currentTime.format(callForDate.getTime());
final DatabaseReference ordersRef = FirebaseDatabase.getInstance().getReference()
.child("Orders")
.child(Prevalent.currentOnlineUsr.getPhone());
DatabaseReference productsRef = FirebaseDatabase.getInstance().getReference().child("Products");
for (String ID : products) {
String orderID = UUID.randomUUID().toString();
String finalLocationJson = locationJson;
productsRef.child(ID).addValueEventListener(new ValueEventListener() {
#Override
public void onDataChange(#NonNull DataSnapshot snapshot) {
ProductModel model = snapshot.getValue(ProductModel.class);
AdminOrder order = new AdminOrder();
order.setOrderID(orderID);
order.setTotalAmount(model.getPrice());
order.setName(deliveryName.getText().toString());
order.setPhone(deliveryPhone.getText().toString());
order.setUid(Prevalent.currentOnlineUsr.getPhone());
order.setCity(deliveryCity.getText().toString());
order.setAddress(deliveryAddress.getText().toString());
if (useCurrentLocation.isChecked()) {
order.setLocation(finalLocationJson);
}
order.setDate(saveCurrentDate);
order.setTime(saveCurrentTime);
order.setState("Not delivered");
order.setMerchantID(model.getMerchantID());
order.setProduct(model.getPname());
order.setProductID(model.getPid());
ordersRef.child(ID).child(orderID).setValue(order).addOnCompleteListener(new OnCompleteListener<Void>() {
#Override
public void onComplete(#NonNull Task<Void> task) {
if (task.isSuccessful()) {
FirebaseDatabase.getInstance().getReference()
.child("Cart")
.child("user")
.child(Prevalent.currentOnlineUsr.getPhone())
.removeValue()
.addOnCompleteListener(new OnCompleteListener<Void>() {
#Override
public void onComplete(#NonNull Task<Void> task) {
if (task.isSuccessful()) {
removeProductsFromDB(products);
loadingBar.dismiss();
showToast("Order Placed");
Intent intent = new Intent(ConfirmOrderActivity.this, HomeActivity.class);
startActivity(intent);
finish();
}
}
}).addOnFailureListener(new OnFailureListener() {
#Override
public void onFailure(#NonNull Exception e) {
showToast("Failed");
loadingBar.dismiss();
}
});
}
}
}).addOnFailureListener(new OnFailureListener() {
#Override
public void onFailure(#NonNull Exception e) {
showToast("Failed");
loadingBar.dismiss();
}
});
}
#Override
public void onCancelled(#NonNull DatabaseError error) {
}
});
}
}
I am new to programming so I am sure there should be a better way of doing this.
Thanks in advance.
Currently developing a Forum App where user who post question will get a notification if someone respond to them. Right now the coding has logical error where the notification does not go into the original poster attribute in the User table inside Firebase
Below is the code to add notification
private void addToHisNotification(String hisUid,String Post_Key,String notification){
String timestamp = ""+System.currentTimeMillis();
HashMap<Object, String> hashMap = new HashMap<>();
hashMap.put("timestamp",timestamp);
hashMap.put("Postkey",Post_Key);
hashMap.put("uid",hisUid);
hashMap.put("notification",notification);
hashMap.put("sUid",current_user_id);
DatabaseReference ref = FirebaseDatabase.getInstance().getReference().child("Users");
ref.child(hisUid).child("Notifications").child(timestamp).setValue(hashMap)
.addOnSuccessListener(new OnSuccessListener<Void>() {
#Override
public void onSuccess(Void aVoid) {
}
})
.addOnFailureListener(new OnFailureListener() {
#Override
public void onFailure(#NonNull Exception e) {
}
});
}
And this is the function to add Answer and will call function Notification
PostAnsButton.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
Userref.child(current_user_id).addValueEventListener(new ValueEventListener() {
#Override
public void onDataChange(#NonNull DataSnapshot dataSnapshot) {
if (dataSnapshot.exists()){
String userName = dataSnapshot.child("Username").getValue().toString();
String profileImg = dataSnapshot.child("profileImage").getValue().toString();
String department = dataSnapshot.child("Department").getValue().toString();
ValidateAnswer(userName,profileImg, department);
addToHisNotification("" + hisUid,"" + Post_Key, "Commented on your post");
AnswerInputText.setText("");
}
}
#Override
public void onCancelled(#NonNull DatabaseError databaseError) {
}
});
}
});
The Null in the image is supposed to be the original poster UID but instead it becomes null. How do I solve this so that the Null becomes the UID of the OP?
I'm trying to store multiple lists of locations inside my database.
I want the keys to follow a pattern, like "LocationList 1 ", "LocationList 2" and so on.
For that I created a list to hold all the keys.
First I want to check if there are any children in the database. If there are none, I want to add a child called "LocationList 1" and store that string in my list.
If there's already a child with that name (meaning my list's size is not 0), then I want to add a key with the name "LocationList <number of items in list here + 1>".
But something in my logic is wrong because the list size is always 0.
Here's my method for retrieving all keys:
private void getKeysList() {
databaseReference.addListenerForSingleValueEvent(new ValueEventListener() {
#Override
public void onDataChange(#NonNull DataSnapshot snapshot) {
if(snapshot.hasChildren()) {
locationKeysString.add(snapshot.getKey());;
}
}
#Override
public void onCancelled(#NonNull DatabaseError error) {
}
});
}
Here's my method for adding a location list to database:
public Task<Void> addLocation(List<Location> locationList, Context context) {
getKeysList();
int itemNumber = locationKeysString.size();
String keyValue = new String();
Task<Void> task;
if (itemNumber == 0) {
keyValue = "LocationList " + 1;
locationKeysString.add(keyValue);
task = databaseReference
.child(keyValue)
.setValue(locationList)
.addOnSuccessListener(new OnSuccessListener<Void>() {
#Override
public void onSuccess(Void unused) {
Toast.makeText(context, R.string.add_to_database_success, Toast.LENGTH_SHORT).show();
}
})
.addOnFailureListener(new OnFailureListener() {
#Override
public void onFailure(#NonNull Exception e) {
Toast.makeText(context, R.string.add_to_database_failure, Toast.LENGTH_SHORT).show();
}
});
} else {
keyValue = "LocationList " + (itemNumber + 1);
locationKeysString.add(keyValue);
task = databaseReference
.child(keyValue)
.setValue(locationList)
.addOnSuccessListener(new OnSuccessListener<Void>() {
#Override
public void onSuccess(Void unused) {
Toast.makeText(context, R.string.add_to_database_success, Toast.LENGTH_SHORT).show();
}
})
.addOnFailureListener(new OnFailureListener() {
#Override
public void onFailure(#NonNull Exception e) {
Toast.makeText(context, R.string.add_to_database_failure, Toast.LENGTH_SHORT).show();
}
});
}
return task;
}
But when I run my application it keeps adding locations to a single location list in the database, "LocationList 1":
"LocationList 2" is never created.
I've also tried the following:
private void getKeysList() {
databaseReference.addChildEventListener(new ChildEventListener() {
#Override
public void onChildAdded(#NonNull DataSnapshot snapshot, #Nullable String previousChildName) {
locationKeysString.add(snapshot.getKey());
}
[...]);
}
But list size is still 0.
What am I doing wrong? And besides that, is there some way I can improve my code?
Thank you.
Edit: Those two methods, getKeysList() and addLocation() are the only places in my code where I refer to my locationKeysString list at all.
Other than that I call addLocation() only once in my onStop() method of my main activity:
#Override
protected void onStop() {
super.onStop();
MyLocation myLocation = (MyLocation) getApplicationContext();
locationList = myLocation.getLocationList();
DAOLocation daoLocation = new DAOLocation();
daoLocation.addLocation(locationList, this);
}
I have tried all of the StackOverflow methods but all the methods are checking if it's null or not.
I wanted to check the particular strings under the "Users" node. example: (aaaaa) (bbbbb) or the child value in it (username : "aaaaa")
if users enter username as "asaaa" or "bbbbb" in registration will be a prompt error. (i want to check all of the values in all of the nodes of firebase)
I have searched all over the stack overflow but most of the solutions need to know the node names in order to run. I want to retrieve all of the names of the nodes under "Users" back to check.
if a user uses "aaaaa" as a username during registration will be setError in the TextInputLayout.
public class RegisterActivity extends AppCompatActivity {
EditText username, fullname, email, password;
Button register;
TextView txt_login;
public String strUsername;
FirebaseAuth auth;
DatabaseReference reference;
ProgressDialog pd;
private static final String TAG = "RegisterActivity";
private static String users_from_database;
private ArrayList<String> username_list = new ArrayList<>();
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_register);
username = findViewById(R.id.username);
fullname = findViewById(R.id.fullname);
email = findViewById(R.id.email);
password = findViewById(R.id.password);
register = findViewById(R.id.btn_Register);
txt_login = findViewById(R.id.txt_login);
auth = FirebaseAuth.getInstance();
checkForUsername();
txt_login.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
startActivity(new Intent(RegisterActivity.this,HomeActivity.class));
}
});
register.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
pd = new ProgressDialog(RegisterActivity.this);
pd.setMessage("Please wait...");
pd.show();
String str_username = username.getText().toString();
String str_fullname = fullname.getText().toString();
String str_email = email.getText().toString();
String str_password = password.getText().toString();
strUsername = username.getText().toString().trim();
if (!username_list.contains(strUsername)) {
// do your job here , suppose send verification code to phone number
if(TextUtils.isEmpty(str_username) || TextUtils.isEmpty(str_fullname) || TextUtils.isEmpty(str_email) ||
TextUtils.isEmpty(str_password)){
Toast.makeText(RegisterActivity.this,"All fields are required!",Toast.LENGTH_SHORT).show();
pd.dismiss();
} else if (str_password.length() < 6) {
Toast.makeText(RegisterActivity.this,"Password must be over 6 characters.",Toast.LENGTH_SHORT).show();
pd.dismiss();
} else {
register(str_username,str_fullname,str_email,str_password);
}
} else {
username.setError("Username Exist");
}
}
});
}
private void checkForUsername(){
DatabaseReference ref = FirebaseDatabase.getInstance().getReference("Users/");
ref.addListenerForSingleValueEvent(new ValueEventListener() {
#Override
public void onDataChange(#NonNull DataSnapshot snapshot) {
for (DataSnapshot ds : snapshot.getChildren()) {
users_from_database = (String) ds.child("username").getValue();
username_list.add(users_from_database);
StringBuilder stringBuilder = new StringBuilder();
for (String s : username_list) {
stringBuilder.append(s + "\n");
}
Log.d("ZI", stringBuilder.toString());
}
}
#Override
public void onCancelled(#NonNull DatabaseError error) {
Log.d("ZI", "Failed");
}
});
}
private void register(final String username, final String fullname, String email, String password){
auth.createUserWithEmailAndPassword(email, password)
.addOnCompleteListener(RegisterActivity.this, new OnCompleteListener<AuthResult>() {
#Override
public void onComplete(#NonNull Task<AuthResult> task) {
if (task.isSuccessful()){
FirebaseUser firebaseUser = auth.getCurrentUser();
String userID = firebaseUser.getUid();
firebaseUser.sendEmailVerification().addOnSuccessListener(new OnSuccessListener<Void>() {
#Override
public void onSuccess(Void aVoid) {
Toast.makeText(RegisterActivity.this,"Verification Email Has Been Sent.", Toast.LENGTH_SHORT).show();
}
}).addOnFailureListener(new OnFailureListener() {
#Override
public void onFailure(#NonNull Exception e) {
Log.d(TAG, "onFailure: Email not sent" + e.getMessage());
}
});
reference = FirebaseDatabase.getInstance().getReference().child("Users").child(username);
HashMap<String, Object> hashMap = new HashMap<>();
hashMap.put("username",username.toLowerCase());
hashMap.put("fullname",fullname);
hashMap.put("email",email);
hashMap.put("password",password);
hashMap.put("imageurl","");
reference.setValue(hashMap).addOnCompleteListener(new OnCompleteListener<Void>() {
#Override
public void onComplete(#NonNull Task<Void> task) {
if(task.isSuccessful()){
pd.dismiss();
Intent intent = new Intent(RegisterActivity.this,EmailActivity.class);
intent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TASK | Intent.FLAG_ACTIVITY_NEW_TASK);
startActivity(intent);
}
}
});
} else {
pd.dismiss();
Toast.makeText(RegisterActivity.this,"Register Failed",Toast.LENGTH_SHORT).show();
}
}
});
}
}
pic 2
You can create a public path usernames where you just store the usernames that are already used and are publicly visible. When registering a new user you can check there is a username already exists. Also don't try to get all of then to check if a single one exists. Just call the path usernames/{username} and if that is null there username doens't exist. Reading all of them would blow up your Firebase bill.
I have searched all over the stack overflow but most of the solutions need to know the node names in order to run.
Even in your example, you can check if a user exists by checking the existence of the following node in the database:
root/users/$userName
In code should look like this:
DatabaseReference rootRef = FirebaseDatabase.getInstance().getReference();
DatabaseReference usersRef = rootRef.child("Users");
DatabaseReference userNameRef = usersRef.child("aaaaa");
userNameRef.get().addOnCompleteListener(new OnCompleteListener<DataSnapshot>() {
#Override
public void onComplete(#NonNull Task<DataSnapshot> task) {
if (task.isSuccessful()) {
DataSnapshot snapshot = task.getResult();
if(snapshot.exists()) {
String fullName = snapshot.child("fullName").getValue(String.class);
Log.d("TAG", fullName);
} else {
Log.d("TAG", "The user doesn't exist!");
}
} else {
Log.d("TAG", task.getException().getMessage()); //Don't ignore potential errors!
}
}
});
While #TarikHuber answer it will work, please note that in this case, it's not necessary to create an additional node to hold all usernames, since your database structure already does that. So in terms of checking if a user exists:
root/users/$userName
It's the exact same thing as:
root/usernames/$userName
Since the nodes in the Realtime Database are represented by pairs of keys and values, please note that the keys are unique. So there is no way you can have duplicate nodes. As each node can be considered a Map.
However, if by chance you can have multiple users in the database sharing the same user name, then you should use a query as in the following lines of code:
Query queryByUserName = usersRef.orderByChild("username").equalTo("aaaaa");
queryByUserName.get().addOnCompleteListener(new OnCompleteListener<DataSnapshot>() {
#Override
public void onComplete(#NonNull Task<DataSnapshot> task) {
if (task.isSuccessful()) {
for (DataSnapshot ds : task.getResult().getChildren()) {
if(ds.exists()) {
String fullName = ds.child("fullName").getValue(String.class);
Log.d("TAG", fullName);
} else {
Log.d("TAG", "The user doesn't exist!");
}
}
} else {
Log.d("TAG", task.getException().getMessage()); //Don't ignore potential errors!
}
}
});
According to your screenshot, in both cases, the result in the logcat will be:
james
P.S. While #ZahidIslam answer might also work, downloading the entire "Users" node and performing the check on the client is not the best option, as it's considered very costly. It's a waste of bandwidth and resources.
Edit:
According to you last comment:
I think u misunderstood me. I want to search thru all the nodes under the rootNodes
There is no way you can create a Query that can search under all nodes inside your database. You can, however, download the entire database and do the filtering on the client, but this is very costly and not recommended.
The best option that you have is to create a separate query for each and every node, but only if all the children have the same fields. Or you can keep the users only in the "Users" node (as you do right now), and the code in my answer will always work perfectly fine.
Yes you can do it by following steps .
get all username child from your DatabaseReference and add it to a ArrayList.
Check user provided username is available in ArrayList (from step 1) or not . If contains then set error , otherwise do your job to complete registration .
Update- I think you are performing button click for registration before executing / finished checkForUsername(); method. So the if...else statement not working properly and its overriding data . It was my mistake . We should perform check all users from database first then perform the next part of registration . So without using checkForUsername() method separately in onCreate() , we will do everything in button on click . check the code -
register.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
pd = new ProgressDialog(LoginActivity.this);
pd.setMessage("Please wait...");
pd.show();
String str_username = username.getText().toString();
String str_fullname = fullname.getText().toString();
String str_email = email.getText().toString();
String str_password = password.getText().toString();
strUsername = username.getText().toString().trim();
DatabaseReference ref = FirebaseDatabase.getInstance().getReference("Users/");
ref.addListenerForSingleValueEvent(new ValueEventListener() {
#Override
public void onDataChange(#NonNull DataSnapshot snapshot) {
for (DataSnapshot ds : snapshot.getChildren()) {
users_from_database = (String) ds.child("username").getValue();
username_list.add(users_from_database);
StringBuilder stringBuilder = new StringBuilder();
for (String s : username_list) {
stringBuilder.append(s + "\n");
}
// Log.d("ZI", stringBuilder.toString());
if (!username_list.contains(strUsername)) {
// do your job here , suppose send verification code to phone number
if (TextUtils.isEmpty(str_username) || TextUtils.isEmpty(str_fullname) || TextUtils.isEmpty(str_email) ||
TextUtils.isEmpty(str_password)) {
Toast.makeText(LoginActivity.this, "All fields are required!", Toast.LENGTH_SHORT).show();
pd.dismiss();
} else if (str_password.length() < 6) {
Toast.makeText(LoginActivity.this, "Password must be over 6 characters.", Toast.LENGTH_SHORT).show();
pd.dismiss();
} else {
register(str_username, str_fullname, str_email, str_password);
}
} else {
username.setError("Username Exist");
pd.dismiss();
}
}
}
#Override
public void onCancelled(#NonNull DatabaseError error) {
Log.d("ZI", "Failed");
}
});
}
});
Update- you can check DataSnapshot exist or not . If not exist , then you can set test value to start your database . This will execute only one time . You may check -
register.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
pd = new ProgressDialog(LoginActivity.this);
pd.setMessage("Please wait...");
pd.show();
String str_username = username.getText().toString();
String str_fullname = fullname.getText().toString();
String str_email = email.getText().toString();
String str_password = password.getText().toString();
strUsername = username.getText().toString().trim();
DatabaseReference ref = FirebaseDatabase.getInstance().getReference("Users/");
ref.addListenerForSingleValueEvent(new ValueEventListener() {
#Override
public void onDataChange(#NonNull DataSnapshot snapshot) {
if (!snapshot.exists()) {
HashMap<String, Object> testHash = new HashMap<>();
testHash.put("username", "testusername");
ref.child("test")
.setValue(testHash).addOnCompleteListener(new OnCompleteListener<Void>() {
#Override
public void onComplete(#NonNull Task<Void> task) {
if (task.isSuccessful()) {
ref.keepSynced(true);
Toast.makeText(LoginActivity.this, "Please try again", Toast.LENGTH_SHORT).show();
pd.dismiss();
} else {
Log.d("ZI", "Failed ", task.getException());
}
}
});
} else {
for (DataSnapshot ds : snapshot.getChildren()) {
users_from_database = (String) ds.child("username").getValue();
username_list.add(users_from_database);
StringBuilder stringBuilder = new StringBuilder();
for (String s : username_list) {
stringBuilder.append(s + "\n");
}
Log.d("ZI", stringBuilder.toString());
if (!username_list.contains(strUsername)) {
// do your job here , suppose send verification code to phone number
if (TextUtils.isEmpty(str_username) || TextUtils.isEmpty(str_fullname) || TextUtils.isEmpty(str_email) ||
TextUtils.isEmpty(str_password)) {
Toast.makeText(LoginActivity.this, "All fields are required!", Toast.LENGTH_SHORT).show();
pd.dismiss();
} else if (str_password.length() < 6) {
Toast.makeText(LoginActivity.this, "Password must be over 6 characters.", Toast.LENGTH_SHORT).show();
pd.dismiss();
} else {
register(str_username, str_fullname, str_email, str_password);
}
} else {
username.setError("Username Exist");
pd.dismiss();
}
}
}
}
#Override
public void onCancelled(#NonNull DatabaseError error) {
Log.d("ZI", "Failed");
}
});
}
});
I'm storing multiple images at once in Firebase Storage and I need to get the URL of each one of them in the Firebase databse.
Here's the code:
private void SaveVersus() {
comment = Comment.getText().toString();
if (imageUri==null||imageUri2==null){
Toast.makeText(this, "...Select a Image...", Toast.LENGTH_SHORT).show();
}
else if(imageUri!=null&&imageUri2!=null&&imageUri3==null&&imageUri4==null) {
//Save2ImagesFirebase();
List<Uri> uri = Arrays.asList(imageUri,imageUri2);
storeMultipleImages(uri);
}
else if(imageUri!=null&&imageUri2!=null&&imageUri3!=null&&imageUri4==null){
//Save3ImagesFirebase();
List<Uri> uri2 = Arrays.asList(imageUri,imageUri2,imageUri3);
storeMultipleImages(uri2);
}
else if(imageUri!=null&&imageUri2!=null&&imageUri3!=null&&imageUri4!=null){
//Save4ImagesFirebase();
List<Uri> uri3 = Arrays.asList(imageUri,imageUri2,imageUri3,imageUri4);
storeMultipleImages(uri3);
}
}
public void storeImage(Uri imageUri) {
StorageReference filepath = mStorage.child("Versus Images").child(imageUri.getLastPathSegment());
filepath.putFile(imageUri).addOnCompleteListener(new OnCompleteListener<UploadTask.TaskSnapshot>() {
#Override
public void onComplete(#NonNull Task<UploadTask.TaskSnapshot> task) {
if (task.isSuccessful()){
downloadURL = task.getResult().getUploadSessionUri().toString();
Toast.makeText(ImageVersus.this, "Versus Published", Toast.LENGTH_SHORT).show();
GetInDB();
}
else{
Toast.makeText(ImageVersus.this, "..Error..", Toast.LENGTH_SHORT).show();
}
}
});
}
private void GetInDB() {
mDatabase.child(current_userID).addValueEventListener(new ValueEventListener() {
#Override
public void onDataChange(#NonNull DataSnapshot dataSnapshot) {
if(dataSnapshot.exists()){
String username = dataSnapshot.child("Username").getValue().toString();
HashMap InfoMap = new HashMap<>();
InfoMap.put("username",username);
InfoMap.put("imageUrl",downloadURL);
versusDBRef.child(current_userID).updateChildren(InfoMap);
}
}
#Override
public void onCancelled(#NonNull DatabaseError databaseError) {
}
});
}
public void storeMultipleImages(List<Uri> imageUris) {
for (Uri uri : imageUris) {
storeImage(uri);
}
}
The problem is that, in the hashmap, I can only put the URL of one image and I need to get multiple URLs depending on what the amount of pictures the user select, if they chose two, then in the hashmap must be two URL's and so on.