How to get last node in Firebase? - java

I'm working on a chat app where user can see last message of conversation. But I am stuck with this situation where i am unable to get last message.
I have tried this query like
DatabaseReference getLastMessageRef =
FirebaseDatabase.getInstance().getReference("FriendsMessages");
Query query1 = getLastMessageRef.child(common.currentUser.getPhone()).child(id).orderByKey().limitToLast(1);
Where common.currentUser.getPhone is number/id of current user and id is id of other person.
And database structure is like DATABASE STRUCTURE PICTURE
private void getAllMessages() {
Query query = FirebaseDatabase.getInstance().getReference("FriendsMessages").child(common.currentUser.getPhone());
FirebaseRecyclerOptions<MessageModel> options = new FirebaseRecyclerOptions.Builder<MessageModel>()
.setQuery(query,MessageModel.class)
.build();
adapter = new FirebaseRecyclerAdapter<MessageModel, ShowAllMessageViewHolder>(options) {
#Override
protected void onBindViewHolder(#NonNull final ShowAllMessageViewHolder holder, int position, #NonNull final MessageModel model) {
String id = adapter.getRef(position).getKey();
DatabaseReference getFriendDataRef = FirebaseDatabase.getInstance().getReference("User");
DatabaseReference getLastMessageRef = FirebaseDatabase.getInstance().getReference("FriendsMessages");
getFriendDataRef.child(id).addValueEventListener(new ValueEventListener() {
#Override
public void onDataChange(DataSnapshot dataSnapshot) {
if (dataSnapshot.exists()){
String dp = dataSnapshot.child("img").getValue().toString();
String name = dataSnapshot.child("name").getValue().toString();
holder.MessageName.setText(name);
Picasso.with(getBaseContext()).load(dp).into(holder.messageDp);
}
}
#Override
public void onCancelled(DatabaseError databaseError) {
}
});
Query query1 = getLastMessageRef.child(common.currentUser.getPhone()).child(id).orderByKey().limitToLast(1);
query1.addListenerForSingleValueEvent(new ValueEventListener() {
#Override
public void onDataChange(DataSnapshot dataSnapshot) {
String mesaage = (String) dataSnapshot.child("message").getValue();
Toast.makeText(mContext, ""+mesaage, Toast.LENGTH_SHORT).show();
}
#Override
public void onCancelled(DatabaseError databaseError) {
}
});
}
#NonNull
#Override
public ShowAllMessageViewHolder onCreateViewHolder(#NonNull ViewGroup parent, int viewType) {
View view = LayoutInflater.from(parent.getContext())
.inflate(R.layout.card_message_view,parent,false);
return new ShowAllMessageViewHolder(view);
}
};
showAllMessages.setAdapter(adapter);
adapter.notifyDataSetChanged();
}
I am getting null string.

One thing to remember is that Firebase keys are always Strings. And when strings are ordered, are ordered lexicographically.
If you want to get the last element, add to each message object a new property that can hold a timestamp. This is how you can add it to the database and get it back. In the end, simply create a query and order the elements according to this new timestamp property and call limitToLast(1). That's it!

Related

Retrieve subcollection data from Firestore in Android

I keep failed to retrieve the data from subcollection "Diary" when trying on click on a RecyclerView. What I want is when I on click on a RecyclerView, it will display that data stored in the "Diary". What's the problem with my codes?
RecyclerView Java codes:
private void setUpRecyclerView() {
fStore = FirebaseFirestore.getInstance();
FirebaseUser user = FirebaseAuth.getInstance().getCurrentUser();
Query query = fStore.collection("Users").document(user.getUid()).collection("Diary").orderBy("Date", Query.Direction.ASCENDING);
FirestoreRecyclerOptions<ModelClass> options = new FirestoreRecyclerOptions.Builder<ModelClass>()
.setQuery(query, ModelClass.class)
.build();
adapters = new CustomAdapter(options,this);
adapters.startListening();
recyclerView.setLayoutManager(new LinearLayoutManager(this));
recyclerView.setAdapter(adapters);
new ItemTouchHelper(new ItemTouchHelper.SimpleCallback(0,
ItemTouchHelper.LEFT | ItemTouchHelper.RIGHT) {
#Override
public boolean onMove(#NonNull RecyclerView recyclerView, #NonNull RecyclerView.ViewHolder viewHolder, #NonNull RecyclerView.ViewHolder target) {
return false;
}
#Override
public void onSwiped(#NonNull RecyclerView.ViewHolder viewHolder, int direction) {
adapters.deleteItem(viewHolder.getAdapterPosition());
}
}).attachToRecyclerView(recyclerView);
}
#Override
public void onItemClick(final DocumentSnapshot snapshot, int position) {
final ModelClass diary = snapshot.toObject(ModelClass.class);
String id = snapshot.getId();
startActivity(new Intent(diary_user.this,onClickRecyclerViewDiary_user.class));
Toast.makeText(diary_user.this,"Position: " + position + "ID: " + id,Toast.LENGTH_SHORT).show();
}
Stored data Java codes:
check.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
FirebaseUser user = fAuth.getCurrentUser();
String uid = user.getUid();
String id = fStore.collection("Users").document(user.getUid()).collection("Diary").document().getId();
DocumentReference df = fStore.collection("Users").document(user.getUid()).collection("Diary").document(id);
Map<String, Object> diaryInfo = new HashMap<>();
diaryInfo.put("Symptom", symptom.getEditText().getText().toString());
diaryInfo.put("Note", note.getEditText().getText().toString());
diaryInfo.put("Date", dateButton.getText().toString());
diaryInfo.put("ID",id);
SimpleDateFormat tf = new SimpleDateFormat("hh:mm a");
String currentTime = tf.format(Calendar.getInstance().getTime());
time.setText(currentTime);
diaryInfo.put("Time", time.getText().toString());
feeling = spinner.getSelectedItem().toString();
diaryInfo.put("Feeling", feeling);
df.set(diaryInfo).addOnSuccessListener(new OnSuccessListener() {
#Override
public void onSuccess(Object o) {
Toast.makeText(add_diary_user.this, "Data successfully stored", Toast.LENGTH_SHORT).show();
startActivity(new Intent(add_diary_user.this, diary_user.class));
finish();
}
}).addOnFailureListener(new OnFailureListener() {
#Override
public void onFailure(#NonNull Exception e) {
Toast.makeText(add_diary_user.this, e.toString(), Toast.LENGTH_SHORT).show();
}
});
}
});
Retrieve data Java codes:
private void getDiary() {
fStore = FirebaseFirestore.getInstance();
FirebaseUser user = fAuth.getCurrentUser();
String id = fStore.collection("Users").document(user.getUid()).collection("Diary").document().getId();
fStore.collection("Users").document(user.getUid()).collection("Diary");
diary.whereEqualTo("ID", id)
.get()
.addOnCompleteListener(new OnCompleteListener<QuerySnapshot>() {
#Override
public void onComplete(#NonNull Task<QuerySnapshot> task) {
if (task.isSuccessful()) {
for (DocumentSnapshot document : task.getResult()) {
// Do something with your retrieved documents
dateButton.setText((CharSequence) document.getString("Date"));
note.getEditText().setText((CharSequence) document.getString("Note"));
symptom.getEditText().setText((CharSequence) document.getString("Symptom"));
}
}
}
});
}
Database structure:
Output:
I believe the problem in your code is in this line:
String id = fStore.collection("Users").document(user.getUid()).collection("Diary").document().getId();
Where you are using .document().getId(); but without specifying which document you want, which makes id not have the expected value and because of that you don't get any results in the comparison that uses that value later in your execution. To fix that you would need to have this Id stored somewhere and pass it as a parameter to your getDiary() function, or something similar to that.

Android Firebase Query for Multiple values

I want to fetch the all uid's of the doctor whose category is "abc"(example) and then store those retrieved uid's into an array list.
I want same results as displayed by the below sql query:
select uid from doctors where category = "abc";
Code for next activity is written below
private void loadDoctors() {
ArrayList<String> uid = getIntent().getStringArrayListExtra("doctor_list");
for (int i =0;i<uid.size();i++){
DatabaseReference doctors = FirebaseDatabase.getInstance().getReference("Doctors").child(uid.get(i));
Adapter = new FirebaseRecyclerAdapter<DoctorModel, DoctorViewHolder>(
DoctorModel.class,
R.layout.doctors_home,
DoctorViewHolder.class,
doctors
) {
#Override
protected void populateViewHolder(final DoctorViewHolder viewHolder, final DoctorModel model, int position) {
viewHolder.doctor_name.setText(model.getName());
Glide.with(Doctors.this).load(model.getProfileimage()).into(viewHolder.doctor_image);
viewHolder.qualification.setText(model.getQualification());
viewHolder.rating.setText(model.getRating());
}
};
Adapter.notifyDataSetChanged();
doctors_list.setAdapter(Adapter);
}
To solve this, please use the following lines of code:
DatabaseReference rootRef = FirebaseDatabase.getInstance().getReference();
DatabaseReference doctorsRef = rootRef.child("Doctors");
Query categoryQuery = doctorsRef.orderByChild("category").equalTo("Cardiology");
ValueEventListener valueEventListener = new ValueEventListener() {
#Override
public void onDataChange(DataSnapshot dataSnapshot) {
List<String> uidList = new ArrayList<>();
for(DataSnapshot ds : dataSnapshot.getChildren()) {
String uid = ds.getKey();
uidList.add(uid);
}
//Do what you need to do with your list
}
#Override
public void onCancelled(#NonNull DatabaseError databaseError) {
Log.d("TAG", databaseError.getMessage()); //Don't ignore errors!
}
};
categoryQuery.addListenerForSingleValueEvent(valueEventListener);
At the end, you'll have a list full of uids. One more thing to note, because Firebease API is asynchronous, you will be able to use that list only inside onDataChange() method.

how to get selected value from listview

I want to select finance Name and after clicked finance Name i want to get code of same finance. The finance Name is listed into listview.
My Firebase database structure is below:
financeRef.addListenerForSingleValueEvent(new ValueEventListener() {
#Override
public void onDataChange(#NonNull DataSnapshot dataSnapshot) {
for (DataSnapshot snapshot : dataSnapshot.getChildren()) {
//Map<String, Object> data = (Map<String, Object>) snapshot.getValue();
String value = new Gson().toJson(snapshot.getValue());
progressBar.setVisibility(View.GONE);
try {
JSONObject object = new JSONObject(String.valueOf(value));
f = object.getString("Finance Name");
name = snapshot.getKey();
} catch (JSONException e) {
e.printStackTrace();
}
financeName.add(f);
adapter.notifyDataSetChanged();
}
listView.setOnItemClickListener(new AdapterView.OnItemClickListener() {
#Override
public void onItemClick(AdapterView<?> parent, View view, int position, long id) {
Intent intent = new Intent(FinanceNameListActivity.this, CodeAndNameActivity.class);
String abc = (String) ((TextView) view).getText();
intent.putExtra("Name",abc);
startActivity(intent);
finish();
}
});
}
#Override
public void onCancelled(#NonNull DatabaseError databaseError) {
}
});
Get response from firebase and set it to model call or hashmap or array up to you then implement interface for list view click event or simple click event with get position and get value from where you set firebase response.

Firebase keeps changing the value and adding new child

I am trying to load data from firebase database and then I want to add some more data to it and in the end I want it to upload back. But the problem is when the data is being uploaded back it is not stopping after updating the data. It looks like it is under loop and doing the task again and again.
mTempDatabase.addValueEventListener(new ValueEventListener() {
#Override
public void onDataChange(DataSnapshot dataSnapshot) {
if(dataSnapshot.hasChild(mAuth.getCurrentUser().getUid())){
final DatabaseReference newTemp = mTempDatabase.child(mAuth.getCurrentUser().getUid());
final long qntCount = (long) dataSnapshot.child(mAuth.getCurrentUser().getUid()).child("QuantityCount").getValue();
final long foodamount = (long) dataSnapshot.child(mAuth.getCurrentUser().getUid()).child("QuantityCount").getValue();
//final long countfood = (long) dataSnapshot.child(mAuth.getCurrentUser().getUid()).child("QuantityCount").getValue();
mDatabaseBestseller.addValueEventListener(new ValueEventListener() {
#Override
public void onDataChange(DataSnapshot dataSnapshot) {
String foodname = (String) dataSnapshot.child(food_key).child("foodname").getValue();
long foodprice = (long) dataSnapshot.child(food_key).child("foodprice").getValue();
long mfoodprice = foodprice + foodamount;
long mqntCOunt = qntCount +1;
newTemp.child("QuantityCount").setValue(mqntCOunt);
newTemp.child("FoodPrice1").setValue(mfoodprice);
}
#Override
public void onCancelled(DatabaseError databaseError) {
}
});
}
}
#Override
public void onCancelled(DatabaseError databaseError) {
}
});
mTempDatabase.addValueEventListener(new ValueEventListener() {
#Override
public void onDataChange(DataSnapshot dataSnapshot) {
if(!dataSnapshot.hasChild(mAuth.getCurrentUser().getUid())) {
final DatabaseReference newTemp = mTempDatabase.child(mAuth.getCurrentUser().getUid());
mDatabaseBestseller.addValueEventListener(new ValueEventListener() {
#Override
public void onDataChange(DataSnapshot dataSnapshot) {
String foodname = (String) dataSnapshot.child(food_key).child("foodname").getValue();
long foodprice = (long) dataSnapshot.child(food_key).child("foodprice").getValue();
newTemp.child("QuantityCount").setValue(1);
newTemp.child("CountFood1").setValue(1);
newTemp.child("Food1").setValue(foodname);
newTemp.child("FoodPrice1").setValue(foodprice);
}
#Override
public void onCancelled(DatabaseError databaseError) {
}
});
}
}
#Override
public void onCancelled(DatabaseError databaseError) {
}
});
viewHolder.mFoodAddLayout.setVisibility(View.INVISIBLE);
viewHolder.mIncrLayout.setVisibility(View.VISIBLE);
}
});
According to my understanding I have did wrong math while retrieving the data and adding the data back.
addValueEventListener() will always listening to database reference value changes.if you want to stop listening you have to use removeEventListener(valueListener),
But addListenerForSingleValueEvent() executes onDataChange method immediately and after executing that method once, it stops listening to value changes.
You need to use the .addListenerForSingleValueEvent() instead of .addValueEventListener(). The difference is, the second one keep updating every time a value is changed in the database, which keep happening as you update your value inside the function. But, the first method that I am suggesting, just read the values once, which is what you need here.

firebase get data as array

I am trying to implement firebase into my Android app and I want to be able to pull all the entries in firebase in the order they display in into one string array to be put into a ListView
Here is the raw JSON:
[ 5, "quot", "waaaaa", "also a quote", "oh this one is a little longer man", "gosh really long. wow. im very inspired. golly gee wiz" ]
and the code I am using to try and get it:
public class MyActivity extends ListActivity {
ArrayList<String> LIST = new ArrayList<String>();
Boolean wow = true;
Context context = this;
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
Firebase.setAndroidContext(context);
updateList();
}
public void makeList(ArrayList<String> input){
setListAdapter(new ArrayAdapter<String>(this, R.layout.mylist,input));
ListView listView = getListView();
listView.setTextFilterEnabled(true);
listView.setOnItemClickListener(new AdapterView.OnItemClickListener() {
public void onItemClick(AdapterView<?> parent, View view,
int position, long id) {
// When clicked, show a toast with the TextView text
Toast.makeText(getApplicationContext(),
((TextView) view).getText(), Toast.LENGTH_SHORT).show();
}
});
}
public void updateList() {
Firebase myFirebaseRef = new Firebase("https://admin1.firebaseio.com/");
myFirebaseRef.child("0").addValueEventListener(new ValueEventListener() {
#Override
public void onDataChange(DataSnapshot snapshot) {
System.out.println(snapshot.getValue());
int length = Integer.parseInt(snapshot.getValue().toString());
Firebase myFirebaseRef = new Firebase("https://admin1.firebaseio.com/");
for(int i=1; i<length; i++) {
String doIt = Integer.toString(i);
myFirebaseRef.child(doIt).addValueEventListener(new ValueEventListener() {
#Override
public void onDataChange(DataSnapshot snapshot) {
System.out.println(snapshot.getValue());
LIST.add(snapshot.getValue().toString());
}
#Override
public void onCancelled(FirebaseError error) {
}
});
}makeList(LIST);
}
#Override
public void onCancelled(FirebaseError error) {
}
});
}
}
I was thinking that I could set the first (0th) object to be the number of entries and then cycle through the entire file using .getValue but when this is run I get out of memory exceptions and the app force closes. All I am sure of is that the relevant firebase stuff is the issue and not the ListView. Thanks for any tips.
Firstly, your data is stored in a JSON data object (i.e. not an array). You do not want to store sequential, numeric ids in distributed data.
To listen for the first n objects, utilize the query methods and limitToFirst.
int n = 10;
String URL = "https://<your instance>.firebaseio.com";
Firebase ref = new Firebase(URL);
Query queryRef = ref.orderByKey().limitToFirst(n);
queryRef.addChildEventListener(new ChildEventListener() {
#Override
public void onChildAdded(DataSnapshot snapshot, String previousChild) {
Map<String, String> value = (Map<String, String)snapshot.getValue();
System.out.println(snapshot.getKey() + " was " + value.get("message"));
}
// ....
});

Categories