Paginate new data over old data from firestore - java

I am building a chat app and using pagination in conversation screen. First i am loading ten messages the most recent one from firestore and then next 10 and goes on. when first 10 messages are loaded in screen the next 10 messages are loaded below the recent messages but i want to load old messages over new messages here is sample of my code
toolbar =findViewById(R.id.toolbar5);
toolbar.setTitle("");
setSupportActionBar(toolbar);
Objects.requireNonNull(getSupportActionBar()).setDisplayHomeAsUpEnabled(true);
toolbar.setNavigationOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View view) {
finish();
}
});
sendBtn = findViewById(R.id.sendBtn);
textMsg = findViewById(R.id.txtMessage);
profileImg=findViewById(R.id.profile_imageChat);
userName = findViewById(R.id.userName);
userState = findViewById(R.id.userState);
refreshMessages = findViewById(R.id.refreshMessages);
mChat = new ArrayList<>();
firestore =FirebaseFirestore.getInstance();
auth =FirebaseAuth.getInstance();
docref = firestore.collection("users").document(getUser());
documentReference = firestore.collection("users").document(Objects.requireNonNull(auth.getCurrentUser()).getUid());
//setting up online and last seen status
docref.addSnapshotListener(new EventListener<DocumentSnapshot>() {
#SuppressLint("SetTextI18n")
#Override
public void onEvent(#Nullable DocumentSnapshot documentSnapshot, #Nullable FirebaseFirestoreException e) {
if(e!=null)
Log.d("Event",e+"");
if(documentSnapshot != null){
if(documentSnapshot.getBoolean("state").equals(true))
userState.setText("Online");
else
userState.setText(documentSnapshot.getString("offlineDate"));
}
else
Log.d("Error","Null");
}
});
refreshMessages.setOnRefreshListener(new SwipeRefreshLayout.OnRefreshListener() {
#Override
public void onRefresh() {
recieveMessage(auth.getCurrentUser().getUid(),getUser());
}
});
sendBtn.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View view) {
String message = textMsg.getText().toString().trim();
String sender=auth.getCurrentUser().getUid();
if (!message.isEmpty()){
//getting Current time
calendar=Calendar.getInstance();
#SuppressLint("SimpleDateFormat") SimpleDateFormat simpleDateFormat = new SimpleDateFormat("hh:mm a");
final String currentTime = simpleDateFormat.format(calendar.getTime());
//getting current everything
Calendar calendar2 = Calendar.getInstance();
#SuppressLint("SimpleDateFormat") SimpleDateFormat simpleDateFormat1 = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss.SSSXXX");
final String dateSet = simpleDateFormat1.format(calendar2.getTime());
sendMessage(sender,getUser(),message,currentTime,dateSet);
}
else
Toast.makeText(chatScreen.this, "Error", Toast.LENGTH_SHORT).show();
textMsg.setText("");
}
});
constraintLayout=findViewById(R.id.toolbarLayout);
constraintLayout.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View view) {
Intent intent = new Intent(getApplicationContext(), userProfile.class);
intent.putExtra("userid",getUser());
intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
getApplicationContext().startActivity(intent);
}
});
docref.get().addOnSuccessListener(new OnSuccessListener<DocumentSnapshot>() {
#Override
public void onSuccess(DocumentSnapshot documentSnapshot) {
userName.setText(documentSnapshot.getString("Name"));
recieveMessage(auth.getUid(),getUser());
//Do coding For image
storageReference = FirebaseStorage.getInstance().getReference();
final StorageReference profile = storageReference.child("users/"+getUser());
profile.getDownloadUrl().addOnCompleteListener(new OnCompleteListener<Uri>() {
#Override
public void onComplete(#NonNull Task<Uri> task) {
Picasso.get().load(task.getResult()).into(profileImg);
}
});
}
});
//messages recycler view
recyclerView =findViewById(R.id.recyclerSenderView);
recyclerView.setHasFixedSize(true);
recyclerView.setLayoutManager(new LinearLayoutManager(getApplicationContext()));
and here is the function i am calling from onCreate
private void recieveMessage(final String sender , final String reciever) {
colref = FirebaseFirestore.getInstance().collection("chats");
Query next;
if(lastVisible == null)
next = colref.orderBy("dateSet", Query.Direction.DESCENDING).limit(TOTAL_MESSAGES_TO_LOAD);
else
next = colref.orderBy("dateSet").limitToLast(TOTAL_MESSAGES_TO_LOAD).endBefore(lastVisible);
next.addSnapshotListener(new EventListener<QuerySnapshot>() {
#Override
public void onEvent(#Nullable QuerySnapshot queryDocumentSnapshots, #Nullable FirebaseFirestoreException e) {
if(e!= null)
Log.d("onEvent", e+"");
if(queryDocumentSnapshots != null){
// mChat.clear();
//Load item first time
for (QueryDocumentSnapshot ds : queryDocumentSnapshots){
lastvisibleDoc.add(queryDocumentSnapshots.getDocuments().toString());
if(ds.getString("Reciever").equals(sender) && ds.getString("Sender").equals(reciever) ||
ds.getString("Reciever").equals(reciever) && ds.getString("Sender").equals(sender)){
mChat.add(new ChatModel(ds.getString("Sender"),ds.getString("Reciever"),ds.getString("Message"),ds.getString("Time")));
}
}
// Get the last visible document
if(queryDocumentSnapshots.size() > 0){
lastVisible = queryDocumentSnapshots.getDocuments().get(0);
Log.d("VisibleDoc",lastVisible+"");
lastvisibleDoc.clear();
Toast.makeText(chatScreen.this, "wrk", Toast.LENGTH_SHORT).show();
}
adapter = new messgaeAdapter(getApplicationContext(),mChat);
recyclerView.setAdapter(adapter);
adapter.notifyDataSetChanged();
recyclerView.scrollToPosition(mChat.size()-1);
refreshMessages.setRefreshing(false);
}
else
Log.d("Document","null");
}
});
}

In that case you'll want to clear the list of messages by removing the comment markings from this line:
// mChat.clear();
This will remove the previous messages from the list, so that you only see the next page of messages.
I also recommend looking into this code:
adapter = new messageAdapter(getApplicationContext(),mChat);
recyclerView.setAdapter(adapter);
These is no need to create a new adapter when loading the new messages. More idiomatic is to have these two lines in the onCreate so that they happen only once. When you then modify the contents of mChat, you'll call adapter.notifyDataSetChanged() (as you already do) to signal that the data has changed, and the adapter will update the recycler view.

Related

How to stop automatic scroll up in recycler view when increment button is clicked in recycler view item?

When I click the increment/decrement quantity button in recycler view, the recycler view is getting scrolled up automatically. How do I avoid scrolling up automatically??
Below is my code. Please help me.
This is the code in my main activity for recycler view adapter setup
private void loadCartItems() {
//init list
//get orders
shopNameTv.setText(shopname);
cartList = new ArrayList<>();
DatabaseReference reference = FirebaseDatabase.getInstance().getReference("Users");
reference.child(firebaseAuth.getUid()).child("Cart")
.addValueEventListener(new ValueEventListener() {
#Override
public void onDataChange(#NonNull DataSnapshot dataSnapshot) {
//clear list before adding item
cartList.clear();
for (DataSnapshot ds : dataSnapshot.getChildren()) {
CartModel cartModel = ds.getValue(CartModel.class);
Map<String, Object> map = (Map<String, Object>) ds.getValue();
Object price = map.get("Item_Price");
int cost = Integer.parseInt(String.valueOf(price));
allTotalPrice += cost ;
sTotalTv.setText("₹" + allTotalPrice);
allTotalPriceTv.setText("₹" + (allTotalPrice + Integer.parseInt(deliveryFee.replace("₹", ""))));
cartList.add(cartModel);
}
LinearLayoutManager mLayoutManager = new LinearLayoutManager(getApplicationContext());
cartItemsRv.setLayoutManager(mLayoutManager);
cartItemsRv.setItemAnimator(null);
//setup adapter
cartAdapter = new CartAdapter(CartActivity.this, cartList);
//set adapter
cartItemsRv.scrollToPosition(cartList.size());
}
#Override
public void onCancelled(#NonNull DatabaseError error) {
}
});
//allTotalPrice = allTotalPrice + Integer.parseInt(price);
dFeeTv.setText("₹" + deliveryFee);
sTotalTv.setText("₹" + allTotalPrice);
allTotalPriceTv.setText("₹" + (allTotalPrice + Integer.parseInt(deliveryFee.replace("₹", ""))));
}
This is my adapter code
if (Integer.parseInt(stk) == 0) {
Toast.makeText(context, "Product Stock Limit reached", Toast.LENGTH_SHORT).show();
}
else {
holder.incrementBtn.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View view) {
int number = 0;
number = Integer.parseInt(holder.itemQuantityTv.getText().toString().trim());
number++;
//((CartActivity)context).reload();
holder.itemQuantityTv.setText(""+number);
int pe = number * Integer.parseInt(holder.itemPriceEachTv.getText().toString().trim());
holder.itemPriceTv.setText(""+pe);
double tx = Double.parseDouble((((CartActivity)context).allTotalPriceTv.getText().toString().trim().replace("₹","")));
double totalPrice = tx + Double.parseDouble(cartModel.getItem_Price().replace("₹",""));
double deliveryFee = Double.parseDouble((((CartActivity)context).deliveryFee.replace("₹","")));
double sTotalPrice = Double.parseDouble(String.format("%.0f", totalPrice));
((CartActivity)context).allTotalPrice = 0;
((CartActivity)context).sTotalTv.setText("₹"+String.format("%.0f", sTotalPrice));
((CartActivity)context).allTotalPriceTv.setText("₹"+String.format("%.0f", Double.parseDouble(String.format("%.0f", sTotalPrice))));
HashMap<String, Object> hashMap = new HashMap<>();
hashMap.put("Item_Price", "" + pe);
hashMap.put("Item_Quantity", "" + number);
hashMap.put("Available_Stock", "" + availableStock);
//update db
DatabaseReference ref = FirebaseDatabase.getInstance().getReference("Users");
ref.child(firebaseAuth.getUid()).child("Cart").child(cartModel.getItem_PID()).updateChildren(hashMap)
.addOnSuccessListener(new OnSuccessListener<Void>() {
#Override
public void onSuccess(Void aVoid) {
//db updated
// Toast.makeText(context, "Cart updated", Toast.LENGTH_SHORT).show();
}
})
.addOnFailureListener(new OnFailureListener() {
#Override
public void onFailure(#NonNull Exception e) {
//failed updating db
Toast.makeText(context, "Cart not updated", Toast.LENGTH_SHORT).show();
}
});
//To update stock value in cart
int stk_number = 0;
stk_number = Integer.parseInt(holder.stock.getText().toString().trim());
if (stk_number >0 ){
stk_number--;
holder.stock.setText(""+stk_number);
HashMap<String, Object> hashMap1 = new HashMap<>();
hashMap1.put("Stock_left", "" + stk_number);
//update db
DatabaseReference reference = FirebaseDatabase.getInstance().getReference("Users");
reference.child(firebaseAuth.getUid()).child("Cart").child(cartModel.getItem_PID()).updateChildren(hashMap1)
.addOnSuccessListener(new OnSuccessListener<Void>() {
#Override
public void onSuccess(Void aVoid) {
//db updated
// Toast.makeText(context, "Cart updated", Toast.LENGTH_SHORT).show();
}
})
.addOnFailureListener(new OnFailureListener() {
#Override
public void onFailure(#NonNull Exception e) {
//failed updating db
Toast.makeText(context, "Cart not updated", Toast.LENGTH_SHORT).show();
}
});
}
else {
stk_number = 0;
}
}
});
}
Whenever I click increment/decrement button in recycler view item, the recycler view is scrolled up automatically. If I need to increment again, I need to scroll down again every time. So, how to stop this auto-scroll up and make it stay in the same position.
You have to remove the ValueEventListener after successful loading and populating the Adapter. Otherwise, you get an update event after updating the value. This creates a new Adapter which is scrolled to the top.
You can use .get() if you want to read the DB only once:
mDatabase.child("users").child(userId).get().addOnCompleteListener(new OnCompleteListener<DataSnapshot>() {
#Override
public void onComplete(#NonNull Task<DataSnapshot> task) {
if (!task.isSuccessful()) {
Log.e("firebase", "Error getting data", task.getException());
}
else {
Log.d("firebase", String.valueOf(task.getResult().getValue()));
}
}
});
Source: https://firebase.google.com/docs/database/android/read-and-write#read_data_once
In your case:
reference.child(firebaseAuth.getUid()).child("Cart").get().addOnCompleteListener(new OnCompleteListener<DataSnapshot>() {
...
}

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.

addsnapshotlistener triggers even though there is no update in Firebase

In my app, the homepage activity holds a sectioned recyclerview, in which the value is initiated by querying Firebase. The data retrieval and the recyclerview was working well at first.
Then, I tried to implement addsnapshotlistener to automatically update my activity without needing the user to refresh the page independently.
However, when I run my code, the recyclerview repeated the same sectioned recyclerview twice.
Here is the code for my activity:
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
getSupportActionBar().hide();
setContentView(R.layout.homepage);
mAuth = FirebaseAuth.getInstance();
db = FirebaseFirestore.getInstance();
///storageRef = FirebaseStorage.getInstance().getReference();
FirebaseUser user = FirebaseAuth.getInstance().getCurrentUser();
UserId = FirebaseAuth.getInstance().getCurrentUser().getUid();
MainRecyclerView = findViewById(R.id.MainContainer);
SignoutButton = findViewById(R.id.SignOutbutton);
checkUserType();
SignoutButton.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View view) {
FirebaseAuth.getInstance().signOut();
///mAuth.GoogleSignInApi.signOut(apiClient);
Intent i = new Intent(HomePage.this, Login.class);
startActivity(i);
}
});
///queries data from firebase
initData();
BottomNavigationView bottomNavigationView = findViewById(R.id.bottomNavigationView);
bottomNavigationView.setSelectedItemId(R.id.appointment);
bottomNavigationView.setOnNavigationItemSelectedListener(new BottomNavigationView.OnNavigationItemSelectedListener() {
#Override
public boolean onNavigationItemSelected(#NonNull MenuItem item) {
switch (item.getItemId()){
case R.id.search:
startActivity(new Intent(getApplicationContext(),Search.class));
overridePendingTransition(0,0);
return true;
case R.id.appointment:
return true;
case R.id.profile:
startActivity(new Intent(getApplicationContext(),Profile.class));
overridePendingTransition(0,0);
return true;
}
return false;
}
});
UpdateToken();
}
#Override
protected void onStart() {
super.onStart();
sectionList.clear();
apnmntList.clear();
CollectionReference colref = db.collection("appointmentsColl").document(UserId)
.collection("Date");
///check for updates inside of the collections
HPListener= colref.addSnapshotListener(new EventListener<QuerySnapshot>() {
#Override
public void onEvent(#Nullable QuerySnapshot value, #Nullable FirebaseFirestoreException error) {
for (QueryDocumentSnapshot document : value) {
///query all the values again
db.collection("appointmentsColl").document(UserId)
.collection("Date").document(document.getId())
.collection("appointmentsID")
.get().addOnCompleteListener(new OnCompleteListener<QuerySnapshot>() {
#Override
public void onComplete(#NonNull Task<QuerySnapshot> task) {
apnmntList = new ArrayList();
for (DocumentSnapshot querysnapshot: task.getResult()){
apnmtDetails details = new apnmtDetails(
querysnapshot.getString("customer name"),
querysnapshot.getString("barberID"),
querysnapshot.getString("shop name"),
querysnapshot.getString("name"),
querysnapshot.getString("type"),
querysnapshot.getString("status"),
querysnapshot.getString("price"),
querysnapshot.getString("time slot"));
apnmntList.add(details);
section = new Section(document.getString("date"),apnmntList);
}
///notify recyclerview
sectionList.add(section);
mainRecyclerAdapter.notifyDataSetChanged();
}
});
}
}
});
}
#Override
protected void onStop() {
super.onStop();
HPListener.remove();
}
private void checkUserType() {
DocumentReference docRef = db.collection("Users").document(UserId);
docRef.addSnapshotListener(new EventListener<DocumentSnapshot>() {
#Override
public void onEvent(#Nullable DocumentSnapshot value, #Nullable FirebaseFirestoreException error) {
if (value.exists()) {
userType = "Users";
} else {
userType = "Barbers";
}
}
});
}
private void initData(){
db.collection("appointmentsColl").document(UserId)
.collection("Date")
.get()
.addOnCompleteListener(new OnCompleteListener<QuerySnapshot>() {
#Override
public void onComplete(#NonNull Task<QuerySnapshot> task) {
if (task.isSuccessful()) {
for (QueryDocumentSnapshot document : task.getResult()) {
///getting the list of appointments and their details
db.collection("appointmentsColl").document(UserId)
.collection("Date").document(document.getId())
.collection("appointmentsID")
.get().addOnCompleteListener(new OnCompleteListener<QuerySnapshot>() {
#Override
public void onComplete(#NonNull Task<QuerySnapshot> task) {
apnmntList = new ArrayList();
for (DocumentSnapshot querysnapshot: task.getResult()){
apnmtDetails details = new apnmtDetails(
querysnapshot.getString("customer name"),
querysnapshot.getString("barberID"),
querysnapshot.getString("shop name"),
querysnapshot.getString("name"),
querysnapshot.getString("type"),
querysnapshot.getString("status"),
querysnapshot.getString("price"),
querysnapshot.getString("time slot"));
///adding appointmnets into an arraylist
apnmntList.add(details);
///saving the value of the section title and the appointments arraylist inside one object
section = new Section(document.getString("date"),apnmntList);
}
////initializing a new array list with the section's objects
sectionList.add(section);
///initializes the main recyclerview
LinearLayoutManager manager = new LinearLayoutManager(HomePage.this);
manager.setReverseLayout(true);
manager.setStackFromEnd(true);
MainRecyclerView.setLayoutManager(manager);
MainRecyclerView.setAdapter(mainRecyclerAdapter);
}
});
}
}else{
Toast.makeText(HomePage.this,"failed",Toast.LENGTH_SHORT).show();
}
}
}).addOnFailureListener(new OnFailureListener() {
#Override
public void onFailure(#NonNull Exception e) {
Log.i("Check", e.toString() );
}
});
}
private void UpdateToken() {
FirebaseUser firebaseUser= FirebaseAuth.getInstance().getCurrentUser();
String refreshToken= FirebaseInstanceId.getInstance().getToken();
Token token= new Token(refreshToken);
FirebaseDatabase.getInstance().getReference("Tokens").child(FirebaseAuth.getInstance().getCurrentUser().getUid()).setValue(token);
}
Here is what my output looks like before and after implementing addsnapshotlistener:
Before
After
I tinkered with the addsnapshotlistener for a while because I was not sure whether it is the cause for the problem, so I tried to replace the method inside the addsnapshotlistener with:
finish();
startActivity(getIntent()
I thought this would work, but when I tried to run my code, the homepage started to refresh itself endlessly without stopping.
I tried to search for people with the same problem as my own, but the posts that I find stated that their addsnapshotlistener triggers correctly but return twice the instance of the data.
The method triggers itself when I open my activity, and it triggers itself even if there are no updates in Firebase.
I would appreciate it if anyone can help me with this problem or maybe guide me to any link or post that can help solve my problem.
You mention that your data retrieval was working well at first. Have you changed anything recently?
From reading your code, I cannot see where you are handling any errors you might encounter. A listener may fail due to a security setting change or an invalid query.
It would help if you implemented an error callback to help you better understand what has happened. For example, you can capture the error message as e and output the error.
if (e != null) {
System.err.println("Listen failed: " + e);
return;
}
Documentation:
db.collection("cities")
.addSnapshotListener(new EventListener<QuerySnapshot>() {
#Override
public void onEvent(#Nullable QuerySnapshot snapshots,
#Nullable FirestoreException e) {
if (e != null) {
System.err.println("Listen failed: " + e);
return;
}
for (DocumentChange dc : snapshots.getDocumentChanges()) {
if (dc.getType() == Type.ADDED) {
System.out.println("New city: " + dc.getDocument().getData());
}
}
}
});

Display Firestore Doc by Id on click, from fragment to activity

So, I've been using the Google's Friendlyeats example as guide. I changed it a bit in order to use Butterknife but had issues when trying to open a single doc (fragment) and show its content in the following activity.
I'm using a recyclerview to show the summarize data and then I want to show the full individual data on an activity. It's really not that much info, just four textviews.
Because of this, I decided to stick to the original example as much as I could to see what was up. Still same error. I can open the following activity but no data is being displayed.
I'm already three months behind lmao. please help!
here's the code:
MessageAdapter.java
#Override
public void onBindViewHolder(#NonNull ViewHolder holder, int position) {
holder.bind(getSnapshot(position), mListener);
}
static class ViewHolder extends RecyclerView.ViewHolder {
public ViewHolder(View itemView) {
super(itemView);
headerView = itemView.findViewById(R.id.message_item_header);
senderView = itemView.findViewById(R.id.message_item_sender);
dateView = itemView.findViewById(R.id.message_item_date);
imageView = itemView.findViewById(R.id.message_item_image);
actualMessageView = itemView.findViewById(R.id.actual_message);
}
public void bind(final DocumentSnapshot snapshot,
final OnMessageSelectedListener listener) {
Messages messages = snapshot.toObject(Messages.class);
imageView.setImageResource(R.drawable.logo_app_off);
headerView.setText(messages.getHeader());
senderView.setText(messages.getSender());
actualMessageView.setText(messages.getMessage());
dateView.setText(messages.getDate());
itemView.setOnClickListener(v -> {
if (listener != null) {
listener.onMessageSelectedListener(snapshot);
}
});
}
}
}
HomeFragment.java
#Override
public void onMessageSelectedListener(DocumentSnapshot message) {
Intent intent = new Intent(getActivity(), MessageDetailActivity.class);
intent.putExtra(KEY_MESSAGE_ID, message.getId());
startActivity(intent);
}
private void initFirestore() {
mFirestore = FirebaseFirestore.getInstance();
mQuery = mFirestore.collection("messages")
.orderBy("date", Query.Direction.DESCENDING)
.limit(LIMIT);
}
private void initRecyclerView() {
if (mQuery == null) {
Log.w(TAG, "No query, not initializing RecyclerView");
}
mAdapter = new MessageAdapter(mQuery, this) {
#Override
protected void onDataChanged() {
if (getItemCount() == 0) {
mMessagesRecycler.setVisibility(View.GONE);
mEmptyView.setVisibility(View.VISIBLE);
} else {
mMessagesRecycler.setVisibility(View.VISIBLE);
mEmptyView.setVisibility(View.GONE);
}
}
#Override
protected void onError(FirebaseFirestoreException e) {
Snackbar.make(view.findViewById(android.R.id.content),
"Error: check logs for info.", Snackbar.LENGTH_LONG).show();
}
};
mMessagesRecycler.setLayoutManager(new LinearLayoutManager(getActivity()));
mMessagesRecycler.setAdapter(mAdapter);
}
DetailMessageActivity.java
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_message_detail);
String messageId = getIntent().getExtras().getString(KEY_MESSAGE_ID);
if (messageId == null) {
throw new IllegalArgumentException("Must pass extra " + KEY_MESSAGE_ID);
}
mFirestore = FirebaseFirestore.getInstance();
mMessageRef = mFirestore.collection("messages").document(messageId);
}
#Override
public void onEvent(DocumentSnapshot snapshot, FirebaseFirestoreException e) {
if (e != null) {
Log.w(TAG, "message:onEvent", e);
return;
}
onMessageLoaded(snapshot.toObject(Messages.class));
}
private void onMessageLoaded(Messages message) {
mDetailedHeader.setText(message.getHeader());
mDetailedHeader.setText(message.getSender());
mDetailedMessage.setText(message.getMessage());
mDetailedDate.setText(message.getDate());
}
}

FirebaseRecyclerAdapter Search

I have implemented a FirebaseRecyclerAdapter to populate cities from the database in to the RecyclerView. After several fails to implement a search feature I am seeking for help. I would like to let users search for a particular city by typing the city's name (postName). The idea is to populate all of the available cities at the beginning and the desired city after its name is typed in the search field.
My code to populate the view is:
searchField = view.findViewById(R.id.search_field);
searchButton = view.findViewById(R.id.imageButton);
searchButton.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
String search_field = searchField.getText().toString().trim();
initialiseScreen(view, search_field);
Toast.makeText(getContext(), search_field, Toast.LENGTH_SHORT).show();
}
});
String search_field = null;
initialiseScreen(view, search_field);
return view;
}
private void initialiseScreen(final View view, String searchText) {
Query postQuery = mDataRef.orderByChild("postName").startAt(searchText).endAt(searchText + "\uf8ff");
mDataRef.keepSynced(true);
recyclerView = view.findViewById(R.id.post_RV);
recyclerView.setLayoutManager(new LinearLayoutManager(getActivity()));
recyclerView.setAdapter(mPostViewAdapter);
FirebaseRecyclerOptions postOptions = new FirebaseRecyclerOptions.Builder<Post>()
.setQuery(postQuery, Post.class).build();
mPostViewAdapter = new FirebaseRecyclerAdapter<Post, PostViewHolder>(postOptions) {
#Override
protected void onBindViewHolder(PostViewHolder holder, int position, final Post model) {
final String post_key = getRef(position).getKey();
holder.setPostCityImage(model.getImageURL());
holder.setPostCityName(model.getPostName());
holder.setLikeBtn(post_key);
//When is clicked once go to city fragment
holder.cityImg.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
//Add code here
Intent singlePostIntent = new Intent(getActivity(), CitiesActivity.class);
singlePostIntent.putExtra("blog_id", post_key);
startActivity(singlePostIntent);
}
});
//Likes button
holder.likes.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
mProccessLike = true;
String postId = model.getmUid();
mDatabaseLikesRef.addValueEventListener(new ValueEventListener() {
#Override
public void onDataChange(DataSnapshot dataSnapshot) {
if(mProccessLike) {
if (dataSnapshot.child(post_key).hasChild(current_user_id)) {
mDatabaseLikesRef.child(post_key).child(current_user_id).removeValue();
mProccessLike = false;
} else {
mDatabaseLikesRef.child(post_key).child(current_user_id).setValue("RandomValue");
mProccessLike = false;
}
}
}
#Override
public void onCancelled(DatabaseError databaseError) {
}
});
}
});
//
}
Btw it populates only one city if instead of String search_field = null; I write something like String search_field = "Calp, Spain";

Categories