Firebase - Sometimes value is not saving - android

Take a look at this GIF I recorded:
This is the database of a counter app I'm making. When a user increments, count gets added along with the count under
users:{
UID:{
count: x
}
}
However, if you can notice in the GIF, sometimes, the upper count gets incremented but the one under users doesn't. Here's the code I'm saving it with:
database = database.child("users").child(auth.getCurrentUser().getUid()).child("count");
final DatabaseReference finalDatabase = database;
database.addListenerForSingleValueEvent(new ValueEventListener() {
#Override
public void onDataChange(DataSnapshot dataSnapshot) {
//Get the latest int
final int[] i = {Integer.parseInt(button.getText().toString())};
//add to the user's count with an onFailureListener
finalDatabase.setValue(i[0]++).addOnFailureListener(new OnFailureListener() {
#Override
public void onFailure(#NonNull Exception e) {
Log.e(TAG,"Adding user's count failed: " + e.getMessage());
}
}).addOnSuccessListener(new OnSuccessListener<Void>() {
#Override
public void onSuccess(Void aVoid) {
//Now add to the original
DatabaseReference database = FirebaseDatabase.getInstance().getReference();
database.child("Campaigns").child(key).child("count").setValue(i[0]++).addOnFailureListener(new OnFailureListener() {
#Override
public void onFailure(#NonNull Exception e) {
Log.e(TAG, "Error: " + e.getMessage());
}
});
}
});
None of the onFailure methods get called. So why is this happening?

You can instead listen to the users node to count the total count. Here's an example
private Map<String, Long> userCount = new HashMap<>();
private Long totalCount = 0L;
private void addTotalCountListener() {
FirebaseDatabase.getInstance().getReference().child("users").addChildEventListener(new ChildEventListener() {
#Override
public void onChildAdded(DataSnapshot dataSnapshot, String s) {
User user = dataSnapshot.getValue(User.class);
userCount.put(dataSnapshot.getKey(), user.getCount);
totalCount += user.getCount();
}
#Override
public void onChildChanged(DataSnapshot dataSnapshot, String s) {
// subtract the total count with the previous count
totalCount -= userCount.get(dataSnapshot.getKey());
// then add the new count
User user = dataSnapshot.getValue(User.class);
userCount.put(dataSnapshot.getKey(), user.getCount);
totalCount += user.getCount();
}
});
}

Related

Can't get the total value of 2 children in Firebase database - Android

I have a method that will upload an app order. You can get the price from database (harga) and amount from the user, but I can't get the total from that. It always gets value as 0.
So here's my code:
public void uploadImg() {
if (FilePathUri != null) {
progressDialog.setTitle("Process...");
progressDialog.show();
StorageReference storageReference2 = storageReference.child(System.currentTimeMillis() + "." + GetFileExtension(FilePathUri));
storageReference2.putFile(FilePathUri).addOnSuccessListener(new OnSuccessListener<UploadTask.TaskSnapshot>() {
#Override
public void onSuccess(final UploadTask.TaskSnapshot taskSnapshot) {
final String ukuran = UkuranPasFoto.getSelectedItem().toString().trim();
final int jumlah = Integer.parseInt(JumlahPasFoto.getText().toString().trim());
final String catatan = inputCatatan.getText().toString().trim();
final int status = 0;
databaseHarga.child("harga").child("pasFoto").addValueEventListener(new ValueEventListener() {
#Override
public void onDataChange(#NonNull DataSnapshot dataSnapshot) {
int harga = dataSnapshot.child(ukuran).getValue(Integer.class);
int total = harga*jumlah;
progressDialog.dismiss();
Toast.makeText(getApplicationContext(),"Sucess !",Toast.LENGTH_LONG).show();
PesanPasFoto ImageUploadInfo = new PesanPasFoto(uid, ukuran, jumlah, catatan, total, status, taskSnapshot.getUploadSessionUri().toString());
String ImageUploadId = database.push().getKey();
database.child(ImageUploadId).setValue(ImageUploadInfo);
}
#Override
public void onCancelled(#NonNull DatabaseError databaseError) {
}
});
}
});
} else {
Toast.makeText(PasFotoActivity.this,"Please Select Image or Fill the blank",Toast.LENGTH_LONG).show();
}
}
here's my database
As you can see that "total" value is always 0
and there's nothing wrong in logcat

How to read data from RecyclerView and make comparison?

Hi I want to read the display data from RecyclerView and make comparison.
This my layout for the activity:
What I want to do is to read all data from RecyclerView and compare with Daily Calorie Suggestion.
After reading all data, I need to make comparisons on how many times the user have taken above, less or sufficient total calories as shown in the "Analysis of Total Calories Consumed of Last 7 Days"
The code:
#Override
protected void onStart() {
Query query = ref.orderByChild("timeStamp").limitToLast(7).endAt(Date);
super.onStart();
if (query != null) {
query .addValueEventListener(new ValueEventListener() {
#Override
public void onDataChange(#NonNull DataSnapshot dataSnapshot) {
if (dataSnapshot.exists()) {
userHighlights = new ArrayList<>();
for (DataSnapshot ds : dataSnapshot.getChildren()) {
userHighlights.add(ds.getValue(HighightsModel.class));
requiredCalorieRef = FirebaseDatabase.getInstance().getReference("Users").child(FirebaseAuth.getInstance().getCurrentUser().getUid());
requiredCalorieRef.addListenerForSingleValueEvent(new ValueEventListener() {
#Override
public void onDataChange(#NonNull DataSnapshot dataSnapshot) {
String userCalorieSuggestion = String.valueOf((dataSnapshot.child("daily calorie").getValue()));
int daily_calorie = Integer.parseInt(userCalorieSuggestion);
}
#Override
public void onCancelled(#NonNull DatabaseError databaseError) {
}
});
}
HighlightsAdapter highlightsAdapter = new HighlightsAdapter(userHighlights);
highlightsRV.setAdapter(highlightsAdapter);
}
}
#Override
public void onCancelled(#NonNull DatabaseError databaseError) {
Toast.makeText(UserNewHighlights.this, databaseError.getMessage(),
Toast.LENGTH_SHORT).show();
}
});
}
}
This is my firebase:
Do I have to write a new code to solve this problem or else? Any help will be much appreciated. Thanks
As #MasoudDarzi mentioned, it's not related to the RecyclerView.
You can try something like this:
#Override
public void onDataChange(#NonNull DataSnapshot dataSnapshot) {
if (dataSnapshot.exists()) {
userHighlights = new ArrayList<>();
for (DataSnapshot ds : dataSnapshot.getChildren()) {
userHighlights.add(ds.getValue(HighightsModel.class));
requiredCalorieRef = FirebaseDatabase.getInstance().getReference("Users").child(FirebaseAuth.getInstance().getCurrentUser().getUid());
requiredCalorieRef.addListenerForSingleValueEvent(new ValueEventListener() {
#Override
public void onDataChange(#NonNull DataSnapshot dataSnapshot) {
String userCalorieSuggestion = String.valueOf((dataSnapshot.child("daily calorie").getValue()));
int daily_calorie = Integer.parseInt(userCalorieSuggestion);
}
#Override
public void onCancelled(#NonNull DatabaseError databaseError) {
}
});
}
HighlightsAdapter highlightsAdapter = new HighlightsAdapter(userHighlights);
highlightsRV.setAdapter(highlightsAdapter);
// do calculation here with userHighlights
int countExceeded = 0, countBelow = 0, countSufficient = 0;
for (HighightsModel h : userHighlights) {
if (h.totalCalorie > daily_calorie) {
countExceeded++;
} else if (h.totalCalorie < daily_calorie) {
countBelow++;
} else {
countSufficient++;
}
}
// update your TextView with the count numbers
// todo
}
}
so The brute force solution is to have a for in your data after getting the 7 days average.
for (your 7 days data){
// check if your data is lower or higher than the average
// and store number of higher or lower
}
looking for a better solution?
I have solved my problem by adding another child at History node. Whereby, previously I have only these for History :
but I add new child which is called STATUS, the status is updated from previous activity as seen the pic below:
so what I did for the code is :
private void upDateAnalysisAbove() {
DatabaseReference ref = FirebaseDatabase.getInstance().getReference("History");
DatabaseReference mRef = ref.child(FirebaseAuth.getInstance().getCurrentUser().getUid());
Query mQuery = mRef.orderByChild("status").equalTo("ABOVE").limitToLast(7);
mQuery.addValueEventListener(new ValueEventListener() {
#Override
public void onDataChange(DataSnapshot dataSnapshot) {
String value = String.valueOf(dataSnapshot.getChildrenCount());
int values = Integer.parseInt(value);
txt_above_output.setText(values + " times(s)");
upDateAnalysisLess(values);
}
#Override
public void onCancelled(DatabaseError databaseError) {
}
});
}
//LESS
private void upDateAnalysisLess(int values) {
DatabaseReference ref = FirebaseDatabase.getInstance().getReference("History");
DatabaseReference mRef = ref.child(FirebaseAuth.getInstance().getCurrentUser().getUid());
Query mQuery = mRef.orderByChild("status").equalTo("LESS").limitToFirst(7);
mQuery.addValueEventListener(new ValueEventListener() {
#Override
public void onDataChange(DataSnapshot dataSnapshot) {
String valueLess = String.valueOf(dataSnapshot.getChildrenCount());
int values_Less = Integer.parseInt(valueLess);
if (values_Less == 0){
txt_less_output.setText(values_Less + " times(s)");
}
if (values > values_Less){
int finalCount = values - values_Less ;
txt_less_output.setText(finalCount + " times(s)");
}
if (values <values_Less){
int finalCount = values_Less - values ;
txt_less_output.setText(finalCount + " times(s)");
}
updateSuff();
}
#Override
public void onCancelled(DatabaseError databaseError) {
}
});
}
//SUFFICIENT
private void updateSuff() {
DatabaseReference ref = FirebaseDatabase.getInstance().getReference("History");
DatabaseReference mRef = ref.child(FirebaseAuth.getInstance().getCurrentUser().getUid());
Query mQuery = mRef.orderByChild("status").equalTo("SUFFICIENT").limitToFirst(7);
mQuery.addValueEventListener(new ValueEventListener() {
#Override
public void onDataChange(DataSnapshot dataSnapshot) {
String value = String.valueOf(dataSnapshot.getChildrenCount());
int suffValue = Integer.parseInt(value);
if (suffValue == 0) {
txt_sufficient_output.setText(suffValue + " times(s)");
}
if (suffValue != 0){
txt_sufficient_output.setText(suffValue + " times(s)");
}
}
#Override
public void onCancelled(DatabaseError databaseError) {
}
});
}
Here is the output:
credit to this post that helped me a lot, and thanks for those who tried to help me.

Find out when does Query finish loading the latest added item

I have a function which write data into database
private void startCommenting() {
final String comment_val = meditComment.getText().toString().trim();
meditComment.setText("");
if (!TextUtils.isEmpty(comment_val)) {
mProgress.show();
final DatabaseReference newPost = mComment.child(post_key).push();
final String commentkey = newPost.getKey();
mUser.addValueEventListener(new ValueEventListener() {
#Override
public void onDataChange(DataSnapshot dataSnapshot) {
Map<String,Object> checkoutData=new HashMap<>();
checkoutData.put("time",ServerValue.TIMESTAMP);
newPost.setValue(checkoutData);
newPost.child("comment").setValue(comment_val);
newPost.child("uid").setValue(dataSnapshot.child("id").getValue());
newPost.child("blogpost").setValue(dataSnapshot.child("blogkey").getValue());
newPost.child("userimage").setValue(dataSnapshot.child("image").getValue());
newPost.child("username").setValue(dataSnapshot.child("name").getValue());
}
#Override
public void onCancelled(DatabaseError databaseError) {
}
});
}
}
After this function was called, a Query was made to get the data which contains the right post_key in the child ("blogpost").
mpostComment.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View view) {
startCommenting();
mQueryCurrentComment = mComment.child(post_key).orderByChild("blogpost").equalTo(post_key);
mQueryCurrentComment.addValueEventListener(new ValueEventListener() {
#Override
public void onDataChange(DataSnapshot dataSnapshot) {
String currentuserid;
String lastuserid = "";
String currentcommentuid;
for (DataSnapshot dsp : dataSnapshot.getChildren()) {
currentuserid = dsp.child("uid").getValue().toString();
Log.d(TAG, "user newid: " + currentuserid);
Log.d(TAG, "user oldid: " + lastuserid);
if (currentuserid.equals(lastuserid)) {
} else {
final DatabaseReference newCommentLike = mComment.child(currentuserid).push();
Map<String, Object> checkTime = new HashMap<>();
checkTime.put("time", ServerValue.TIMESTAMP);
newCommentLike.setValue(checkTime);
newCommentLike.child("location").setValue(location_key);
newCommentLike.child("category").setValue(category_key);
newCommentLike.child("pressed").setValue("false");
newCommentLike.child("message").setValue(" has also commented your post. ");
newCommentLike.child("blogpost").setValue(post_key);
newCommentLike.child(post_key).setValue(true);
}
lastuserid = currentuserid;
}
}
#Override
public void onCancelled(DatabaseError databaseError) {
}
});
}
});
However, the Query was triggered twice, one before the new item was added, another after new item was added, which looks like below:
How can I only perform the actions inside Query after the newest item was added and not twice? Any help is appreciated!

Callback in Firebase android

After create data on Firebase. I try retrieving data from Firebase. But I have problem, I think may be Log.d(TAG,list.size()) run before ref.addChildEventListener(childEventListener); complete. Who can help me ?
public class NewFirebase extends AppCompatActivity {
List < Product > list = new ArrayList < > ();
private static final String TAG = "Firebase";
DatabaseReference ref;
#Override
protected void onCreate(#Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
Firebase.setAndroidContext(this);
ref = FirebaseDatabase.getInstance().getReference();
ChildEventListener childEventListener = new ChildEventListener() {
#Override
public void onChildAdded(DataSnapshot dataSnapshot, String previousChildName) {
Log.d(TAG, "onChildAdded:" + dataSnapshot.getKey());
// A new comment has been added, add it to the displayed list
Product comment = dataSnapshot.getValue(Product.class);
for (DataSnapshot child: dataSnapshot.getChildren()) {
Product post = child.getValue(Product.class);
list.add(post);
}
// ...
}
#Override
public void onChildChanged(DataSnapshot dataSnapshot, String previousChildName) {
Log.d(TAG, "onChildChanged:" + dataSnapshot.getKey());
}
#Override
public void onChildRemoved(DataSnapshot dataSnapshot) {
Log.d(TAG, "onChildRemoved:" + dataSnapshot.getKey());
}
#Override
public void onChildMoved(DataSnapshot dataSnapshot, String previousChildName) {
Log.d(TAG, "onChildMoved:" + dataSnapshot.getKey());
}
#Override
public void onCancelled(DatabaseError databaseError) {
Log.w(TAG, "postComments:onCancelled", databaseError.toException());
}
};
ref.addChildEventListener(childEventListener);
Log.d(TAG, list.size() + "");
}
class RetrievingData extends AsyncTask < Void, Void, Void > {
#Override
protected Void doInBackground(Void...voids) {
return null;
}
}
}
You need to take a second approach to how you are structuring your code, or even take a look at the definition of callback/listener itself.
The addChildEventListener() method assigns a callback and initiates a query for retrieving the result. That is, of course, done in background.
Using listeners will never work that way, that's why they were made for, to don't follow line-by-line execution. If you want to get some result from them, you need to put the code inside their methods, which is when they give you some response. Can take milliseconds, seconds, even minutes, but don't expect to be so immediate to be quicker than the execution of the next line that it was posted to execution.
Take a look at https://www.firebase.com/docs/android/guide/retrieving-data.html.
If you want to see the size of the list that you get from Firebase database, you should use addValueEventListener instead of addChildEventListener
List<Product> commentList = new ArrayList<>();
myRef.addValueEventListener(new ValueEventListener() {
public void onDataChange(DataSnapshot snapshot) {
for (DataSnapshot postSnapshot: snapshot.getChildren()) {
Product comment = postSnapshot.getValue(Product.class);
commentList.add(comment);
}
// here you can print the size of your list
Log.d(TAG,list.size())
}
public void onCancelled(FirebaseError firebaseError) {
System.out.println("The read failed: " + firebaseError.getMessage());
}
});

Get bulk value from firebase and store in sqlite into android app

Hi I was trying firebase with , My server has around 300 records which is getting synced with my app in 3 to four minutes in single, single way
cant it be like get record in set of 50 or something ??
If user is coming online after very long time then also I need this batching.
If user is installing app first time then also i need to download bulk record from firebase database
I am using
ValueEventListener valueEventListener = new ValueEventListener() {
#Override
public void onDataChange(DataSnapshot dataSnapshot) {
Log.e(TAG, "addListenerForSingleValueEvent:onDataChange" + dataSnapshot.getValue());
reference.removeEventListener(valueEventListener);
}
#Override
public void onCancelled(DatabaseError databaseError) {
Log.e(TAG, "addListenerForSingleValueEvent:onCancelled" + databaseError.getMessage());
}
};
and
public class DBService extends Service {
private static final String TAG = DBService.class.getName();
private StartApplication application;
private ObjectMapper objectMapper;
#Override
public void onCreate() {
super.onCreate();
application = ((StartApplication) getApplication());
FirebaseDatabase database = FirebaseDatabase.getInstance();
DatabaseReference reference = database.getReference();
objectMapper = new ObjectMapper();
ChildEventListener childEventListener = new ChildEventListener() {
#Override
public void onChildAdded(DataSnapshot dataSnapshot, String previousChildName) {
try {
String json = objectMapper.writeValueAsString(dataSnapshot.getValue());
Job job = objectMapper.readValue(json, Job.class);
ContentValues values = ContentValuesParser.parseJobs(job);
Uri uri = getContentResolver().insert(TableContract.JobsEntry.CONTENT_URI, values);
Log.d(TAG, "child add id " + job.getId() + " Uri " + uri.getEncodedPath());
} catch (Exception e) {
Log.e(TAG, e.getMessage(), e);
}
//Uri uri = getContentResolver().insert(TableContract.JobsEntry.CONTENT_URI, values);
}
#Override
public void onChildChanged(DataSnapshot dataSnapshot, String previousChildName) {
try {
String json = objectMapper.writeValueAsString(dataSnapshot.getValue());
Job job = objectMapper.readValue(json, Job.class);
ContentValues values = ContentValuesParser.parseJobs(job);
Uri uri = getContentResolver().insert(TableContract.JobsEntry.CONTENT_URI, values);
Log.d(TAG, "child changed id " + job.getId() + " Uri " + uri.getEncodedPath());
} catch (Exception e) {
Log.e(TAG, e.getMessage(), e);
}
}
#Override
public void onChildRemoved(DataSnapshot dataSnapshot) {
}
#Override
public void onChildMoved(DataSnapshot dataSnapshot, String previousChildName) {
}
#Override
public void onCancelled(DatabaseError databaseError) {
}
};
reference.child("jobs").addChildEventListener(childEventListener);
}
#Override
public IBinder onBind(Intent intent) {
return null;
}}
Have you tried Querying data?
Query queryRef = ref.orderByChild("weight").limitToLast(50);
//This will fetch the last 50 children.
queryRef.addChildEventListener(new ChildEventListener() {
#Override
public void onChildAdded(DataSnapshot snapshot, String previousChild) {
System.out.println(snapshot.getKey());
}

Categories

Resources