I have orders collection in firestore:
And I have Sellers collection and inside Sellers collection have another Fruits collection :
I want to get data in orders collection only orders collection fruit_ID equals Sellers/Fruits collection Document ID and add into recyclerview
Is it possible?
Activity class:
package com.example.freshbucket.Seller;
import android.os.Bundle;
import android.support.annotation.NonNull;
import android.support.v7.app.AppCompatActivity;
import android.support.v7.widget.LinearLayoutManager;
import android.support.v7.widget.RecyclerView;
import android.support.v7.widget.helper.ItemTouchHelper;
import android.util.Log;
import android.widget.Toast;
import com.example.freshbucket.Adapter.OrdersSellerRecylerAdapter;
import com.example.freshbucket.Model.PlaceOrder;
import com.example.freshbucket.R;
import com.firebase.ui.firestore.FirestoreRecyclerOptions;
import com.google.firebase.auth.FirebaseAuth;
import com.google.firebase.firestore.CollectionReference;
import com.google.firebase.firestore.DocumentSnapshot;
import com.google.firebase.firestore.EventListener;
import com.google.firebase.firestore.FirebaseFirestore;
import com.google.firebase.firestore.FirebaseFirestoreException;
import com.google.firebase.firestore.Query;
import com.google.firebase.firestore.QuerySnapshot;
import javax.annotation.Nullable;
import static android.support.constraint.Constraints.TAG;
public class SellerGetOrdersActivity extends AppCompatActivity {
String fid, pro;
private FirebaseAuth mAuth = FirebaseAuth.getInstance();
String user_id = mAuth.getCurrentUser().getUid();
private FirebaseFirestore db = FirebaseFirestore.getInstance();
private CollectionReference orders = db.collection("Orders");
private CollectionReference sellers = db.collection("Sellers/"+user_id+"/Fruits");
private OrdersSellerRecylerAdapter adapter;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_seller_get_orders);
setupRecyclerView();
}
private void setupRecyclerView()
{
Query query =orders.orderBy("timestamp", Query.Direction.DESCENDING).whereEqualTo("fruit_ID",fid);
FirestoreRecyclerOptions<PlaceOrder> options = new FirestoreRecyclerOptions.Builder<PlaceOrder>().setQuery(query, PlaceOrder.class).build();
adapter = new OrdersSellerRecylerAdapter(options);
RecyclerView recyclerView = findViewById(R.id.ordersReView);
recyclerView.setHasFixedSize(true);
recyclerView.setLayoutManager(new LinearLayoutManager(this));
recyclerView.setAdapter(adapter);
//swipe delete
new ItemTouchHelper(new ItemTouchHelper.SimpleCallback(0, ItemTouchHelper.LEFT| ItemTouchHelper.RIGHT) {
#Override
public boolean onMove(#NonNull RecyclerView recyclerView, #NonNull RecyclerView.ViewHolder viewHolder, #NonNull RecyclerView.ViewHolder viewHolder1) {
return false;
}
#Override
public void onSwiped(#NonNull RecyclerView.ViewHolder viewHolder, int i) {
adapter.deleteItem(viewHolder.getAdapterPosition());
}
}).attachToRecyclerView(recyclerView);
}
#Override
protected void onStart() {
super.onStart();
adapter.startListening();
sellers.addSnapshotListener(new EventListener<QuerySnapshot>() {
#Override
public void onEvent(#Nullable QuerySnapshot queryDocumentSnapshots, #Nullable FirebaseFirestoreException e) {
if (e != null) {
Log.d(TAG, "Error:" + e.getMessage());
} else {
for (DocumentSnapshot doc :queryDocumentSnapshots){
fid = doc.getId();
// pro = doc.getString("province");
// fid = doc.getString("fruit_ID");
Toast.makeText(SellerGetOrdersActivity.this, "Register error:" +fid , Toast.LENGTH_SHORT).show();
}
}
}
});
}
#Override
protected void onStop() {
super.onStop();
adapter.stopListening();
}
}
Adapter:
package com.example.freshbucket.Adapter;
import android.content.Context;
import android.support.annotation.NonNull;
import android.support.v7.widget.RecyclerView;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.EditText;
import android.widget.TextView;
import com.example.freshbucket.Model.PlaceOrder;
import com.example.freshbucket.R;
import com.firebase.ui.firestore.FirestoreRecyclerAdapter;
import com.firebase.ui.firestore.FirestoreRecyclerOptions;
public class OrdersSellerRecylerAdapter extends FirestoreRecyclerAdapter<PlaceOrder, OrdersSellerRecylerAdapter.OrdersSellerHolder> {
Context context;
public OrdersSellerRecylerAdapter(#NonNull FirestoreRecyclerOptions<PlaceOrder> options) {
super(options);
}
#Override
protected void onBindViewHolder(#NonNull final OrdersSellerHolder holder, int position, #NonNull final PlaceOrder model) {
holder.txtfruitname.setText(model.getName());
holder.txtqun.setText(model.getQun());
holder.txtcusname.setText(model.getCustomer_Name());
holder.txtaddress1.setText(model.getAddressLine1());
holder.txtaddress2.setText(model.getAddressLine2());
holder.txtcity.setText(model.getCity());
}
#NonNull
#Override
public OrdersSellerHolder onCreateViewHolder(#NonNull ViewGroup viewGroup, int i) {
View v = LayoutInflater.from(viewGroup.getContext()).inflate(R.layout.order_list_item_seller,viewGroup, false);
context = viewGroup.getContext();
return new OrdersSellerHolder(v);
}
class OrdersSellerHolder extends RecyclerView.ViewHolder{
TextView txtfruitname, txtqun, txtcusname, txtaddress1, txtaddress2, txtcity;
EditText tctBprice;
public OrdersSellerHolder(#NonNull View itemView) {
super(itemView);
txtfruitname = itemView.findViewById(R.id.fruitnametext);
txtqun = itemView.findViewById(R.id.fruitquntext);
txtcusname = itemView.findViewById(R.id.cusnametext);
txtaddress1 = itemView.findViewById(R.id.addres1text);
txtaddress2 = itemView.findViewById(R.id.addres2text);
txtcity = itemView.findViewById(R.id.citytext);
}
}
public void deleteItem(int position) {
getSnapshots().getSnapshot(position).getReference().delete();
}
}
I want to get data in orders collection only orders collection
fruit_ID
OK, you want to get fruit_ID?
equals Sellers/Fruits collection Document ID and add into recyclerview
and you want to get fruit_ID, which equals with Sellers/Fruits ?
like if (fruit_ID.equals(sellerFruits_ID) {// get fruit_ID}
I will try to answer it.
PROBLEM
1. you as a seller and have your seller uid in your Sellers collection and want to get V4x1Dh..
2. You have buyer uid in your Orders collection and want to get 83Fmf..
3. You want to get Banana in Sellers/Fruits, which the Banana as id.
Lastly, you want to load datas of Sellers/Fruits into recyclerView because
you want to get data in orders collection only orders collection
fruit_ID
ANSWER
Answer number one: Please retrieve the Sellers ids and get V4x1Dh based ViewHolder position that I will explain later.
Answer number two: Please retrieve the Orders ids and get 83Fmf based ViewHolder position that I will explain later.
Answer number two: Please retrieve the Sellers Fruits ids let's say sellerFruit_ID and get Banana based ViewHolder position that I will explain later. NOTE: Since Banana in document it will be id.
DETAILS:
Retrieving the Sellers ids and get V4x1Dh:
firebaseFirestore
.collection("Sellers")
.addSnapshotListener(new EventListener<QuerySnapshot>(){
#Override
public void onEvent(QuerySnapshot documentSnapshots, FirebaseFirestoreException e){
for (DocumentChange doc : documentSnapshots.getDocumentChanges()){
if (doc.getType() == DocumentChange.Type.ADDED){
// RETRIEVING Orders id
String orders_ID = doc.getDocument().getId();
YourContentOrdersHere contentOrders = doc.getDocument().toObject(YourContentOrdersHere.class).withId(orders_ID);
// RETRIEVING Sellers id
String sellers_ID = doc.getDocument().getId();
YourContentSellersHere contentSellers = doc.getDocument().toObject(YourContentSellersHere.class).withId(sellers_ID);
contentListOrders.add(contentOrders); //example: List<YourContentOrdersHere> contentList
adapter.notifyDataSetChanged(); // before of course, you add this in onCreate adapterOrders = new YourAdapterOrders(contentListOrders);
contentListSellers.add(contents); //example: List<YourContentSellersHere> contentList
adapter.notifyDataSetChanged(); // before of course, you add this in onCreate adapterSellers = new YourAdapterSellers(contentListSellers);
}
}
}
});
make sure your content class extends the ids
public class YourContentOrdersHere extends OrdersId {
// make your constructor here of course
// make your getter to get id
}
and make OrdersId.class
public class OrdersId{
#Exclude
public String OrdersId;
public <T extends OrdersId> T withId(#NonNull final String id) {
this.OrdersId = id;
return (T) this;
}
}
and last one , from your adapter class retrieving OrdersId. As Example:
#Override
public void onBindViewHolder(ViewHolder holder, int position) {
// GET YOUR `Sellers` id based position and getSellerId() from getter of your content class
String sellers_ID = contentListSeller.get(position).getSellerId(); // don't forget List<YourContentSellers> contentList = new ArrayList<>();
firebaseFirestore
.collection("Sellers")
.document(sellers_ID)
.collection("Fruits")
.document("Banana")
// STORE 'LIKE TAP' USING LIKE BUTTON
holder.likeHome.seOnClickListener(new View.OnClickListener(){
#Override
public void onClick(View v){
/* RETRIEVING VALUE UNDER currentUserId */
firebaseFirestore.collection("Posts/" + postId + "/Likes").document(currentUserId).get().addOnCompleteListener(new OnCompleteListener<DocumentSnapshot>(){
#Override
public void onComplete(#NonNull Task<DocumentSnapshot> task){
if (!task.getResult().exists()) {
/* STORE NEW VALUE */
Map<String, Object> likesMap = new HashMap<>();
likesMap.put("timestamp", FieldValue.serverTimestamp);
firebaseFirestore.collection("Posts/" + postId + "/Likes").document(currentUserId).set(likesMap);
} else {
// retrieve like timestamp
String whenToLike = task.getResult().getString("timestamp");
holder.setWhenToLike(whenToLike);
/* DELETE VALUE */
firebaseFirestore.collection("Posts/" + postId + "/Likes").document(currentUserId).delete();
}
}
});
}
});
}
Related
This question already has answers here:
Firebase Android ListView not being displayed
(1 answer)
FireBase Realtime Database : Recycler View not populating
(1 answer)
W/Firestore: [CustomClassMapper]: No setter/field for class Android
(2 answers)
"No setter/field for field found on class"
(2 answers)
Closed 1 year ago.
I am trying to fetch a students data from Firestore Collection and then display it in Recycler view
My Firestore Collection and Document :
Collection Name is School Code, Document contains Student Info
Model Class :(Student_Model_Class)
package com.example.firestooredemo;
import java.sql.Timestamp;
import java.util.HashMap;
public class sdm {
private HashMap<String, String> QnA;
private String formname;
private String schoolid;
private String standard;
private String studentname;
private String subject;
private Timestamp timestamp;
private sdm(){}
private sdm(HashMap qna,String formname,String schoolid,String standard,String studentname,String subject,Timestamp timestamp){
this.QnA=qna;
this.formname=formname;
this.schoolid=schoolid;
this.standard=standard;
this.studentname=studentname;
this.subject=subject;
this.timestamp=timestamp;
}
public HashMap<String, String> getQnA() {
return QnA;
}
public void setQnA(HashMap<String, String> qnA) {
QnA = qnA;
}
public String getFormname() {
return formname;
}
public void setFormname(String formname) {
this.formname = formname;
}
public String getSchoolid() {
return schoolid;
}
public void setSchoolid(String schoolid) {
this.schoolid = schoolid;
}
public String getStandard() {
return standard;
}
public void setStandard(String standard) {
this.standard = standard;
}
public String getStudentname() {
return studentname;
}
public void setStudentname(String studentname) {
this.studentname = studentname;
}
public String getSubject() {
return subject;
}
public void setSubject(String subject) {
this.subject = subject;
}
public String getTimestamp() {
return timestamp.toString();
}
public void setTimestamp(Timestamp timestamp) {
this.timestamp = timestamp;
}
}
Activity.java :
package com.example.firestooredemo;
import androidx.annotation.NonNull;
import androidx.appcompat.app.AppCompatActivity;
import androidx.recyclerview.widget.LinearLayoutManager;
import androidx.recyclerview.widget.RecyclerView;
import android.content.Intent;
import android.os.Bundle;
import android.util.Log;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.*;
import com.firebase.ui.firestore.FirestoreRecyclerAdapter;
import com.firebase.ui.firestore.FirestoreRecyclerOptions;
import com.google.android.gms.tasks.OnCompleteListener;
import com.google.android.gms.tasks.Task;
import com.google.firebase.firestore.FirebaseFirestore;
import com.google.firebase.firestore.Query;
import com.google.firebase.firestore.QueryDocumentSnapshot;
import com.google.firebase.firestore.QuerySnapshot;
import java.util.List;
public class DisplayRecord extends AppCompatActivity {
TextView Record_Title,DemoD;
private FirebaseFirestore Fs;
private RecyclerView FSList;
private FirestoreRecyclerAdapter<sdm,Student_View_Holder> F_Adapter;
String S_ID,Student;
List<sdm> stud;
int S_id;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_display_record);
FSList=(RecyclerView) findViewById(R.id.RCView);
FSList.setHasFixedSize(true);
FSList.setLayoutManager(new LinearLayoutManager(this));
Intent intent = getIntent();
Fs=FirebaseFirestore.getInstance();
Record_Title= (TextView) findViewById(R.id.RecordTitle);
S_ID = intent.getStringExtra("School ID");
Record_Title.setText("Records of "+S_ID);
Log.d("Datacheck","School :"+S_ID);
S_id=Integer.parseInt(S_ID);
String TAG="Datacheck";
Fs.collection("EM_DEMO2").document("10th_STD").collection(S_ID)
.whereEqualTo("formname","Tourism, Transport and Communication3")
.get()
.addOnCompleteListener(new OnCompleteListener<QuerySnapshot>() {
#Override
public void onComplete(#NonNull Task<QuerySnapshot> task) {
if (task.isSuccessful()) {
for (QueryDocumentSnapshot document : task.getResult()) {
Log.d(TAG, document.getId() + " => " + document.getData().toString());
Student=Student+document.getLong("standard")+"\n"+document.get("subject")+"\n"+document.get("formname")+"\n-----\n";
// stud.add(document.toObject(s1));
Log.d("IMOP",Student);
}
} else {
Log.d(TAG, "Error getting documents: ", task.getException());
}
}
});
//Query Part
Query Q=Fs.collection("EM_DEMO2").document("10th_STD").collection(S_ID).whereEqualTo("formname","Tourism, Transport and Communication3");
// Recycler view Display
FirestoreRecyclerOptions<sdm> Opt=new FirestoreRecyclerOptions.Builder<sdm>()
.setQuery(Q,sdm.class)
.build();
F_Adapter = new FirestoreRecyclerAdapter<sdm, Student_View_Holder>(Opt) {
#NonNull
#Override
public Student_View_Holder onCreateViewHolder(#NonNull ViewGroup parent, int viewType) {
View V= LayoutInflater.from(parent.getContext()).inflate(R.layout.student_data,parent,false);
return new Student_View_Holder(V);
}
#Override
protected void onBindViewHolder(#NonNull Student_View_Holder holder, int position, #NonNull sdm model) {
holder.StudentName.setText(model.getStudentname());
holder.Standard.setText(model.getStandard());
holder.SchoolID.setText(model.getSchoolid()+"");
holder.Subject.setText(model.getSubject());
holder.FormName.setText(model.getFormname());
// holder.Time.setText(model.getTs()+"");
}
};
FSList.setAdapter(F_Adapter);
//View Holder
}
private class Student_View_Holder extends RecyclerView.ViewHolder {
private TextView StudentName,Standard,Subject,SchoolID,FormName,Time;
public Student_View_Holder(#NonNull View itemView) {
super(itemView);
StudentName = itemView.findViewById(R.id.StudentName);
Standard = itemView.findViewById(R.id.Std);
Subject = itemView.findViewById(R.id.Sub);
SchoolID = itemView.findViewById(R.id.SchoolID);
FormName = itemView.findViewById(R.id.FormName);
Time = itemView.findViewById(R.id.Timestamp);
}
}
#Override
protected void onStart() {
super.onStart();
F_Adapter.startListening();
}
#Override
protected void onStop() {
super.onStop();
if(F_Adapter!= null){
F_Adapter.stopListening();
}
}
}
Student_data design :
XML Design Screenshot
But In app Recycler view only display fetched values of Subject,
App Output
I put some log messages in Student Data Model Class,to check if data is being fetched or not. But those logs doesn't even show up
Log Messages :
Logs with Tag : Datacheck
Log with Tag : IMOP
Kindly please help with this,
thanks in advance.
I have been trying to create a chat application and have implemented it using firestore database. The chat functionality works fine but as soon as the screen is filled and some scrolling is required to see the previous messages, the database updates in a weird way and the order becomes random and sometimes recent messages show up and sometimes older messages show up as a new message. I have used timestamp to order them but it doesn't seem to work. Even after using pagination, it didn't help. The data and order seem to change while scrolling the recycler view. I will put up the code and some screen shots for a better understanding.
Message Model.java
public class MessageModel {
String message, senderID, receiverID;
Long timestamp;
public MessageModel() {
}
public MessageModel(String senderID, String receiverID, String message, Long timestamp) {
this.senderID = senderID;
this.receiverID = receiverID;
this.message = message;
this.timestamp = timestamp;
}
public MessageModel(String senderID, String message) {
this.senderID = senderID;
this.message = message;
}
public String getReceiverID() {
return receiverID;
}
public void setReceiverID(String receiverID) {
this.receiverID = receiverID;
}
public String getMessage() {
return message;
}
public void setMessage(String message) {
this.message = message;
}
public Long getTimestamp() {
return timestamp;
}
public void setTimestamp(Long timestamp) {
this.timestamp = timestamp;
}
public String getSenderID() {
return senderID;
}
public void setSenderID(String senderID) {
this.senderID = senderID;
}
}
Message Adapter
import android.content.Context;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.TextView;
import com.example.chatdemo.Models.MessageModel;
import com.example.chatdemo.databinding.ReceiverTextItemBinding;
import com.example.chatdemo.databinding.SenderTextItemBinding;
import com.google.firebase.auth.FirebaseAuth;
import com.google.firebase.auth.FirebaseUser;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.List;
import java.util.Locale;
import androidx.annotation.NonNull;
import androidx.recyclerview.widget.RecyclerView;
public class NewMessageAdapter extends RecyclerView.Adapter {
private ReceiverTextItemBinding receiverTextItemBinding;
private SenderTextItemBinding senderTextItemBinding;
private Context context;
private FirebaseUser fUser;
private int SENDER_VIEW_TYPE = 1, RECEIVER_VIEW_TYPE = 2;
private SimpleDateFormat simpleDateFormat = new SimpleDateFormat("dd-MMM-yy KK:mm a", Locale.US);
private List<MessageModel> mMessage;
public NewMessageAdapter(Context context, List<MessageModel> mMessage) {
this.context = context;
this.mMessage = mMessage;
}
#NonNull
#Override
public RecyclerView.ViewHolder onCreateViewHolder(#NonNull ViewGroup parent, int viewType) {
if (viewType == SENDER_VIEW_TYPE) {
senderTextItemBinding = SenderTextItemBinding.inflate(LayoutInflater.from(parent.getContext()), parent, false);
return new SenderViewHolder(senderTextItemBinding.getRoot());
} else {
receiverTextItemBinding = ReceiverTextItemBinding.inflate(LayoutInflater.from(parent.getContext()), parent, false);
return new ReceiverViewHolder(receiverTextItemBinding.getRoot());
}
}
#Override
public void onBindViewHolder(#NonNull RecyclerView.ViewHolder holder, int position) {
MessageModel messageModel = mMessage.get(position);
if (holder.getClass() == SenderViewHolder.class) {
senderTextItemBinding.tvSenderText.setText(messageModel.getMessage());
senderTextItemBinding.tvSenderTextTime.setText(simpleDateFormat
.format(new Date(Long.parseLong(messageModel.getTimestamp().toString()))));
} else {
receiverTextItemBinding.tvReceiverText.setText(messageModel.getMessage());
receiverTextItemBinding.tvReceiverTextTime.setText(simpleDateFormat
.format(new Date(Long.parseLong(messageModel.getTimestamp().toString()))));
}
}
#Override
public int getItemCount() {
return mMessage.size();
}
#Override
public int getItemViewType(int position) {
fUser = FirebaseAuth.getInstance().getCurrentUser();
if (mMessage.get(position).getSenderID().equals(fUser.getUid())) {
return SENDER_VIEW_TYPE;
} else {
return RECEIVER_VIEW_TYPE;
}
}
public class ReceiverViewHolder extends RecyclerView.ViewHolder {
private TextView receivedMessage, receivedTime;
public ReceiverViewHolder(#NonNull View itemView) {
super(itemView);
receivedMessage = receiverTextItemBinding.tvReceiverText;
receivedTime = receiverTextItemBinding.tvReceiverTextTime;
}
}
public class SenderViewHolder extends RecyclerView.ViewHolder {
private TextView sentMessage, sentTime;
public SenderViewHolder(#NonNull View itemView) {
super(itemView);
sentMessage = senderTextItemBinding.tvSenderText;
sentTime = senderTextItemBinding.tvSenderTextTime;
}
}
}
Chat Activity
import android.app.ProgressDialog;
import android.content.Intent;
import android.net.Uri;
import android.os.Bundle;
import android.util.Log;
import android.view.View;
import android.widget.AbsListView;
import android.widget.Toast;
import com.bumptech.glide.Glide;
import com.example.chatdemo.Adapters.ChatAdapter;
import com.example.chatdemo.Adapters.NewMessageAdapter;
import com.example.chatdemo.Constants.Constants;
import com.example.chatdemo.Models.MessageModel;
import com.example.chatdemo.databinding.ActivityChatDetailBinding;
import com.firebase.ui.firestore.FirestoreRecyclerOptions;
import com.google.android.gms.tasks.OnCompleteListener;
import com.google.android.gms.tasks.OnSuccessListener;
import com.google.android.gms.tasks.Task;
import com.google.firebase.auth.FirebaseAuth;
import com.google.firebase.firestore.CollectionReference;
import com.google.firebase.firestore.DocumentReference;
import com.google.firebase.firestore.DocumentSnapshot;
import com.google.firebase.firestore.EventListener;
import com.google.firebase.firestore.FirebaseFirestore;
import com.google.firebase.firestore.FirebaseFirestoreException;
import com.google.firebase.firestore.ListenerRegistration;
import com.google.firebase.firestore.Query;
import com.google.firebase.firestore.QueryDocumentSnapshot;
import com.google.firebase.firestore.QuerySnapshot;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import androidx.appcompat.app.AppCompatActivity;
import androidx.recyclerview.widget.LinearLayoutManager;
import androidx.recyclerview.widget.RecyclerView;
public class ChatDetailActivity extends AppCompatActivity {
private ActivityChatDetailBinding binding;
private Constants constants;
private MessageModel messageModel;
private FirebaseAuth firebaseAuth;
private FirebaseFirestore firestoreDB;
private String userID;
private FirestoreRecyclerOptions<MessageModel> options;
private ChatAdapter chatAdapter;
public static final String TAG = "paginate";
private NewMessageAdapter newMessageAdapter;
private RecyclerView recyclerView;
private List<MessageModel> mMessage;
private final int limit = 15;
private DocumentSnapshot lastVisible;
private boolean isScrolling = false;
private boolean isLastItemReached = false;
private String senderID, receiverID, receiverName, receiverPhoto;
private CollectionReference collectionReference;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
binding = ActivityChatDetailBinding.inflate(getLayoutInflater());
setContentView(binding.getRoot());
firebaseAuth = FirebaseAuth.getInstance();
firestoreDB = FirebaseFirestore.getInstance();
userID = firebaseAuth.getUid();
constants = new Constants();
senderID = firebaseAuth.getUid();
receiverID = getIntent().getStringExtra("receiverID");
receiverName = getIntent().getStringExtra("receiverName");
receiverPhoto = getIntent().getStringExtra("receiverPhoto");
binding.chatUserName.setText(receiverName);
Glide.with(getApplicationContext())
.load(Uri.parse(receiverPhoto))
.into(binding.chatUserImage);
binding.btnChatBack.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View view) {
// Go back
startActivity(new Intent(ChatDetailActivity.this, MainActivity.class));
}
});
collectionReference = firestoreDB.collection(constants.getChats())
.document(userID)
.collection(constants.getMessages())
.document(receiverID)
.collection(constants.getMessages());
binding.btnSendChat.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View view) {
if (!binding.etMessage.getText().toString().equals("")) {
String message = binding.etMessage.getText().toString().trim();
messageModel = new MessageModel(senderID, receiverID, message, new Date().getTime());
binding.etMessage.setText("");
ProgressDialog progressDialog = new ProgressDialog(ChatDetailActivity.this);
progressDialog.setMessage("Sending...");
progressDialog.show();
firestoreDB.collection(constants.getChats())
.document(userID)
.collection(constants.getMessages())
.document(receiverID)
.collection(constants.getMessages())
.add(messageModel)
.addOnSuccessListener(new OnSuccessListener<DocumentReference>() {
#Override
public void onSuccess(DocumentReference documentReference) {
firestoreDB.collection(constants.getChats())
.document(receiverID)
.collection(constants.getMessages())
.document(userID)
.collection(constants.getMessages())
.add(messageModel)
.addOnSuccessListener(new OnSuccessListener<DocumentReference>() {
#Override
public void onSuccess(DocumentReference documentReference) {
progressDialog.dismiss();
Toast.makeText(ChatDetailActivity.this, "Message Sent", Toast.LENGTH_SHORT).show();
}
});
}
});
progressDialog.dismiss();
}
}
});
collectionReference.addSnapshotListener(new EventListener<QuerySnapshot>() {
#Override
public void onEvent(#Nullable QuerySnapshot value, #Nullable FirebaseFirestoreException error) {
Toast.makeText(ChatDetailActivity.this, "Change", Toast.LENGTH_SHORT).show();
readMessage(userID, receiverID);
}
});
initNewRecycler();
}
private void initNewRecycler() {
recyclerView = binding.chatRecyclerView;
recyclerView.setHasFixedSize(true);
LinearLayoutManager linearLayoutManager = new LinearLayoutManager(getApplicationContext());
linearLayoutManager.setStackFromEnd(false);
linearLayoutManager.setReverseLayout(true);
recyclerView.setLayoutManager(linearLayoutManager);
}
private void readMessage(String userID, String receiverID) {
mMessage = new ArrayList<>();
collectionReference.orderBy("timestamp", Query.Direction.DESCENDING).limit(limit)
.get().addOnSuccessListener(new OnSuccessListener<QuerySnapshot>() {
#Override
public void onSuccess(QuerySnapshot queryDocumentSnapshots) {
mMessage.clear();
for (QueryDocumentSnapshot snapshot : queryDocumentSnapshots) {
MessageModel model = snapshot.toObject(MessageModel.class);
if (model.getReceiverID().equals(userID) && model.getSenderID().equals(receiverID)
|| model.getReceiverID().equals(receiverID) && model.getSenderID().equals(userID)) {
mMessage.add(model);
}
newMessageAdapter = new NewMessageAdapter(ChatDetailActivity.this, mMessage);
recyclerView.setAdapter(newMessageAdapter);
}
}
});
}
}
Firebase firestore database structure
Firebase-root
|
---- chats
|
---- userID
|
---messages
|
---receiverID
|
---messages
|
---- message: "Hello!"
|
---- timestamp: 1498472455940
|
---- senderID: senderID
|
---- receiverID: receiverID
Some sample screenshots of the problem I have been facing
The first screen is what appears when the chat activity is first opened and the messages are displayed. Here everything works fine and the messaging system works.
In the second picture however we can see that when the user scrolls up to see the previous messages, some of them are shown correctly but some of them like "Does it work" and "No perhaps" have different time and some are not in the correct order. This happens frequently whenever the user scrolls the list
This is the problem I have been facing for quite a while now. I am not sure what is causing this kind of behaviour and would love to have some light shed in this issue. If anyone can help, it would be highly appreciated. Thanks.
Facing an error.
I am making a chat application with firebase. where i am sending and printing the data from Firebase Realtime Database. the issue is that whenever i am adding or sending a data into the Firebase Realtime Database, its not only printing the currently added data but also printing the whole data from node Chats again and again wherever any data added into the Firebase Realtime Database.
how can i fix this?
Whats my think to solve the error?
I think removing of event listener which are being attached on call of
getMessage(); can fix the error.
This is my ChatActivity
package com.socialcodia.sherewatan;
import android.content.Intent;
import android.os.Bundle;
import android.view.View;
import android.widget.EditText;
import android.widget.ImageButton;
import android.widget.ImageView;
import android.widget.TextView;
import android.widget.Toast;
import androidx.annotation.NonNull;
import androidx.appcompat.app.AppCompatActivity;
import androidx.appcompat.widget.Toolbar;
import androidx.recyclerview.widget.LinearLayoutManager;
import androidx.recyclerview.widget.RecyclerView;
import com.google.firebase.auth.FirebaseAuth;
import com.google.firebase.auth.FirebaseUser;
import com.google.firebase.database.DataSnapshot;
import com.google.firebase.database.DatabaseError;
import com.google.firebase.database.DatabaseReference;
import com.google.firebase.database.FirebaseDatabase;
import com.google.firebase.database.Query;
import com.google.firebase.database.ValueEventListener;
import com.socialcodia.sherewatan.adapter.ChatAdapter;
import com.socialcodia.sherewatan.model.ChatModel;
import com.socialcodia.sherewatan.storage.Constants;
import com.squareup.picasso.Picasso;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
public class ChatActivity extends AppCompatActivity {
Toolbar toolbar;
private EditText inputMessage;
private ImageButton btnSendMessage;
private TextView toolbarUserName, toolbarUserStatus;
private ImageView toolbarUserImage;
//Firebase
FirebaseAuth firebaseAuth;
FirebaseDatabase firebaseDatabase;
DatabaseReference databaseReference;
DatabaseReference chatDatabaseReference;
FirebaseUser firebaseUser;
RecyclerView chatRecyclerView;
Intent intent;
String toUid;
String myUid;
List<ChatModel> chatList;
ChatAdapter chatAdapter;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_chat);
//init Chat Recycler View
chatRecyclerView = findViewById(R.id.chatRecyclerView);
//set layout manager at chatRecyclerview
LinearLayoutManager layoutManager = new LinearLayoutManager(getApplicationContext());
chatRecyclerView.setLayoutManager(layoutManager);
//Firebase Init
firebaseAuth = FirebaseAuth.getInstance();
firebaseDatabase = FirebaseDatabase.getInstance();
databaseReference = firebaseDatabase.getReference("Users");
chatDatabaseReference = firebaseDatabase.getReference("Chats");
firebaseUser =firebaseAuth.getCurrentUser();
//Init
inputMessage = findViewById(R.id.inputMessage);
btnSendMessage = findViewById(R.id.btnSendMessage);
toolbarUserName = findViewById(R.id.toolbarUserName);
toolbarUserStatus = findViewById(R.id.toolbarUserStatus);
toolbarUserImage = findViewById(R.id.toolbarUserImage);
toolbar = findViewById(R.id.chat_toolbar);
setSupportActionBar(toolbar);
intent = getIntent();
//Data From intent
toUid = intent.getStringExtra("uid");
//Click listener on btn send message
btnSendMessage.setOnClickListener(new View.OnClickListener()
{
#Override
public void onClick(View v) {
ValidateAndSendMessage();
}
});
getMessage();
}
private void ValidateAndSendMessage()
{
String message = inputMessage.getText().toString().trim();
if (message.isEmpty())
{
Toast.makeText(this, "Can't send empty message", Toast.LENGTH_SHORT).show();
}
else
{
sendMessage(message);
}
}
private void sendMessage(String message)
{
HashMap<String, Object> map = new HashMap<>();
map.put("msg",message);
map.put(Constants.TIMESTAMP,System.currentTimeMillis()/1000);
map.put("fromUid",myUid);
map.put("toUid",toUid);
DatabaseReference chatRef = firebaseDatabase.getReference("Chats");
chatRef.push().setValue(map);
inputMessage.setText("");
}
private void getMessage()
{
chatList = new ArrayList<>();
final DatabaseReference chatRef = firebaseDatabase.getReference("Chats");
chatRef.addValueEventListener(new ValueEventListener() {
#Override
public void onDataChange(#NonNull DataSnapshot dataSnapshot) {
for (DataSnapshot ds : dataSnapshot.getChildren())
{
ChatModel chatModel = ds.getValue(ChatModel.class);
if (chatModel.getFromUid().equals(myUid) && chatModel.getToUid().equals(toUid) ||
chatModel.getFromUid().equals(toUid) && chatModel.getToUid().equals(myUid))
{
chatList.add(chatModel);
}
chatAdapter = new ChatAdapter(chatList,getApplicationContext());
chatAdapter.notifyDataSetChanged();
chatRecyclerView.setAdapter(chatAdapter);
}
}
#Override
public void onCancelled(#NonNull DatabaseError databaseError) {
}
});
}
}
This is my ChatAdapter.class
package com.socialcodia.sherewatan.adapter;
import android.content.Context;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.TextView;
import androidx.annotation.NonNull;
import androidx.recyclerview.widget.RecyclerView;
import com.google.firebase.auth.FirebaseAuth;
import com.google.firebase.auth.FirebaseUser;
import com.socialcodia.sherewatan.R;
import com.socialcodia.sherewatan.model.ChatModel;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.List;
public class ChatAdapter extends RecyclerView.Adapter<ChatAdapter.ChatViewHolder> {
List<ChatModel> modelClassList;
Context context;
private static final int MSG_TYPE_RIGHT = 0;
private static final int MSG_TYPE_LEFT = 1;
FirebaseUser firebaseUser;
public ChatAdapter(List<ChatModel> modelClassList, Context context) {
this.modelClassList = modelClassList;
this.context = context;
}
#NonNull
#Override
public ChatViewHolder onCreateViewHolder(#NonNull ViewGroup parent, int viewType) {
if (viewType==MSG_TYPE_RIGHT)
{
View view = LayoutInflater.from(context).inflate(R.layout.chat_right,parent,false);
ChatViewHolder viewHolder = new ChatViewHolder(view);
return viewHolder;
}
else
{
View view = LayoutInflater.from(context).inflate(R.layout.chat_left,parent,false);
ChatViewHolder viewHolder = new ChatViewHolder(view);
return viewHolder;
}
}
#Override
public void onBindViewHolder(#NonNull ChatViewHolder holder, int position) {
String msg = modelClassList.get(position).getMsg();
Long timestamp = modelClassList.get(position).getTimestamp();
holder.tvChatMessage.setText(msg);
holder.tvChatTime.setText(getTime(timestamp));
}
private String getTime(Long timestamp) {
Long ts = timestamp*1000;
SimpleDateFormat sdf = new SimpleDateFormat("hh:mm:a");
String time = sdf.format(new Date(ts));
return time;
}
#Override
public int getItemCount() {
return modelClassList.size();
}
#Override
public int getItemViewType(int position) {
firebaseUser = FirebaseAuth.getInstance().getCurrentUser();
if (modelClassList.get(position).getFromUid().equals(firebaseUser.getUid()))
{
return MSG_TYPE_RIGHT;
}
else
{
return MSG_TYPE_LEFT;
}
}
public class ChatViewHolder extends RecyclerView.ViewHolder
{
private TextView tvChatMessage, tvChatTime;
public ChatViewHolder(#NonNull View itemView) {
super(itemView);
tvChatMessage = itemView.findViewById(R.id.tvChatMessage);
tvChatTime = itemView.findViewById(R.id.tvChatTime);
}
}
}
This is my ChatModel.class
package com.socialcodia.sherewatan.model;
public class ChatModel {
public String fromUid, toUid, msg;
Long timestamp;
public ChatModel() {
}
public ChatModel(String fromUid, String toUid, String msg, Long timestamp) {
this.fromUid = fromUid;
this.toUid = toUid;
this.msg = msg;
this.timestamp = timestamp;
}
public String getFromUid() {
return fromUid;
}
public void setFromUid(String fromUid) {
this.fromUid = fromUid;
}
public String getToUid() {
return toUid;
}
public void setToUid(String toUid) {
this.toUid = toUid;
}
public String getMsg() {
return msg;
}
public void setMsg(String msg) {
this.msg = msg;
}
public Long getTimestamp() {
return timestamp;
}
public void setTimestamp(Long timestamp) {
this.timestamp = timestamp;
}
}
You forgot to clear the modelClassList.
private void getMessage()
{
chatList = new ArrayList<>();
final DatabaseReference chatRef = firebaseDatabase.getReference("Chats");
chatRef.addValueEventListener(new ValueEventListener() {
#Override
public void onDataChange(#NonNull DataSnapshot dataSnapshot) {
chatList.clear(); // Clear list
for (DataSnapshot ds : dataSnapshot.getChildren())
{
ChatModel chatModel = ds.getValue(ChatModel.class);
if (chatModel.getFromUid().equals(myUid) && chatModel.getToUid().equals(toUid) ||
chatModel.getFromUid().equals(toUid) && chatModel.getToUid().equals(myUid))
{
chatList.add(chatModel);
}
chatAdapter = new ChatAdapter(chatList,getApplicationContext());
chatAdapter.notifyDataSetChanged();
chatRecyclerView.setAdapter(chatAdapter);
}
}
#Override
public void onCancelled(#NonNull DatabaseError databaseError) {
}
});
}
That will clear the list as well fix your problem.
Declare HashMap or ArrayList globally and write this code map.clear() or arrayList.clear() at the very beginning of the method from which you are retreiving your data. Hopefully the problem will be solved.
Hey Guys i try to change the Query in Firebase depending on the selected user. But when i update the Query the Recyclerview stops showing data. Below is my Code. I would really appreciate if someone could take a look. I'm using the Recyclerview provided by Firebase. The database I'm using is Firestore.
package com.larinet.veikkokrypczyk.myfamilyandfriends;
import android.os.Bundle;
import android.support.annotation.Nullable;
import android.support.design.widget.Snackbar;
import android.support.v4.app.Fragment;
import android.support.v7.widget.LinearLayoutManager;
import android.support.v7.widget.RecyclerView;
import android.util.Log;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.ProgressBar;
import android.widget.TextView;
import com.firebase.ui.firestore.FirestoreRecyclerAdapter;
import com.firebase.ui.firestore.FirestoreRecyclerOptions;
import com.google.firebase.auth.FirebaseAuth;
import com.google.firebase.auth.FirebaseUser;
import com.google.firebase.firestore.FirebaseFirestore;
import com.google.firebase.firestore.FirebaseFirestoreException;
import com.google.firebase.firestore.Query;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.Locale;
/**
* A simple {#link Fragment} subclass.
*/
public class LocationListFragment extends Fragment {
ProgressBar progressBar;
RecyclerView locationList;
private static final String TAG = "LocationListFragment";
private FirebaseFirestore db;
private FirestoreRecyclerAdapter adapter;
LinearLayoutManager linearLayoutManager;
private FirebaseAuth mAuth;
private FirebaseUser currentUser;
private Query query;
private FirestoreRecyclerOptions<LocationEntity> response;
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
mAuth = FirebaseAuth.getInstance();
}
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
View rootView = inflater.inflate(R.layout.fragment_location_list, container, false);
return rootView;
}
#Override
public void onViewCreated(View view, #Nullable Bundle savedInstanceState) {
super.onViewCreated(view, savedInstanceState);
db = FirebaseFirestore.getInstance();
progressBar = view.findViewById(R.id.progress_bar);
locationList = view.findViewById(R.id.locationdata_rv);
linearLayoutManager = new LinearLayoutManager(getActivity(), LinearLayoutManager.VERTICAL, false);
locationList.setLayoutManager(linearLayoutManager);
currentUser = mAuth.getCurrentUser();
UserEntity user = new UserEntity(currentUser.getDisplayName(), currentUser.getUid());
getInitialData(user);
}
public void getInitialData(UserEntity user){
//FAILED_PRECONDITION: The query requires an index. You can create it here:
query = db.collection("locations").orderBy("date", Query.Direction.DESCENDING).whereEqualTo("id", user.getId());
response = new FirestoreRecyclerOptions.Builder<LocationEntity>()
.setQuery(query, LocationEntity.class)
.build();
attachRecyclerViewAdapter();
adapter.notifyDataSetChanged();
}
public void getLocationDataForUser(UserEntity user){
//FAILED_PRECONDITION: The query requires an index. You can create it here:
query = db.collection("locations").orderBy("date", Query.Direction.DESCENDING).whereEqualTo("id", user.getId());
response = new FirestoreRecyclerOptions.Builder<LocationEntity>()
.setQuery(query, LocationEntity.class)
.build();
adapter.notifyDataSetChanged();
}
private void attachRecyclerViewAdapter() {
adapter = new FirestoreRecyclerAdapter<LocationEntity, FriendsHolder>(response) {
#Override
public void onBindViewHolder(FriendsHolder holder, int position, LocationEntity model) {
progressBar.setVisibility(View.GONE);
holder.locationLat.setText(Double.toString(model.getGeoPoint().getLatitude()));
holder.locationLong.setText(Double.toString(model.getGeoPoint().getLongitude()));
holder.userName.setText(model.getUserName());
SimpleDateFormat sdf = new SimpleDateFormat("dd-MM-yyyy hh:mm", Locale.GERMAN);
String time = sdf.format(model.getDate());
holder.date.setText(time);
holder.itemView.setOnClickListener(v -> {
Snackbar.make(locationList, Double.toString(model.getGeoPoint().getLatitude())+", "+Double.toString(model.getGeoPoint().getLongitude()), Snackbar.LENGTH_LONG)
.setAction("Action", null).show();
});
}
#Override
public FriendsHolder onCreateViewHolder(ViewGroup group, int i) {
View view = LayoutInflater.from(group.getContext())
.inflate(R.layout.recyclerview_row, group, false);
return new FriendsHolder(view);
}
#Override
public void onError(FirebaseFirestoreException e) {
Log.e("error", e.getMessage());
}
};
locationList.setAdapter(adapter);
}
public class FriendsHolder extends RecyclerView.ViewHolder {
TextView locationLat;
TextView locationLong;
TextView userName;
TextView date;
public FriendsHolder(View itemView) {
super(itemView);
locationLat = itemView.findViewById(R.id.locationLat);
locationLong = itemView.findViewById(R.id.locationLong);
userName = itemView.findViewById(R.id.userName);
date = itemView.findViewById(R.id.date);
}
}
#Override
public void onStart() {
super.onStart();
adapter.startListening();
}
#Override
public void onStop() {
super.onStop();
adapter.stopListening();
}
}
so my Solution now looks like the following:
public void getInitialData(UserEntity user){
//FAILED_PRECONDITION: The query requires an index. You can create it here:
query = db.collection("locations").orderBy("date", Query.Direction.DESCENDING).whereEqualTo("id", user.getId());
response = new FirestoreRecyclerOptions.Builder<LocationEntity>()
.setQuery(query, LocationEntity.class)
.build();
attachRecyclerViewAdapter();
adapter.notifyDataSetChanged();
}
public void getLocationDataForUser(UserEntity user){
adapter.stopListening();
//FAILED_PRECONDITION: The query requires an index. You can create it here:
query = db.collection("locations").orderBy("date", Query.Direction.DESCENDING).whereEqualTo("id", user.getId());
response = new FirestoreRecyclerOptions.Builder<LocationEntity>()
.setQuery(query, LocationEntity.class)
.build();
attachRecyclerViewAdapter();
adapter.startListening();
adapter.notifyDataSetChanged();
}
The important part seems to be to stop listening and start listening by your own if you change the query also i need to reinstantiate the Adapter. I honestly don't know if all of this is good practice but it works..
I'm developing real-time messenger application with Parse and want to display all of users in ListView. So I also want to reference if user is online or offline, I tried 'put' method to add column named "online" and put information about it. When it went wrong, I added that column myself, but it still did not work. Here it's what I tried in UserList class at all:
import android.content.Intent;
import android.os.Bundle;
import android.support.v7.app.AppCompatActivity;
import android.view.View;
import android.widget.AdapterView;
import android.widget.ListView;
import com.parse.FindCallback;
import com.parse.ParseException;
import com.parse.ParseUser;
import java.util.ArrayList;
import java.util.List;
public class UserList extends AppCompatActivity {
public static ArrayList<ParseUser> userList;
public static String TAG = "UserList";
public static ParseUser user = new ParseUser();
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_user_list);
updateUserStatus(true);
}
#Override
protected void onDestroy() {
super.onDestroy();
updateUserStatus(false);
}
#Override
protected void onResume() {
super.onResume();
loadUserList();
}
private void updateUserStatus(boolean isOnline) {
user.put("online", isOnline);
user.saveEventually();
//System.out.println("getBoolean's result : " + user.getBoolean("online"));
}
private void loadUserList() {
ParseUser.getQuery().whereNotEqualTo("username", user.getUsername()).findInBackground(new FindCallback<ParseUser>() {
#Override
public void done(List<ParseUser> objects, ParseException e) {
if (objects != null) {
if (objects.size() == 0) System.out.println("No user found");
userList = new ArrayList<>(objects);
ListView list = (ListView) findViewById(R.id.userList);
list.setAdapter(new UserAdapter(UserList.this));
list.setOnItemClickListener(new AdapterView.OnItemClickListener() {
#Override
public void onItemClick(AdapterView<?> adapterView, View view, int i, long l) {
startActivity(new Intent(UserList.this, MainActivity.class));
finish();
}
});
}
else {
System.out.println("exception detected while loading user list");
e.printStackTrace();
}
}
});
}
}
UserAdapter class:
import android.content.Context;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.BaseAdapter;
import android.widget.TextView;
import com.parse.ParseUser;
public class UserAdapter extends BaseAdapter {
public static String TAG = "UserAdapter";
public TextView labelname;
LayoutInflater layoutInflater;
public UserAdapter(Context context){
layoutInflater = LayoutInflater.from(context);
}
#Override
public int getCount() {
return UserList.userList.size();
}
#Override
public ParseUser getItem(int index) {
return UserList.userList.get(index);
}
#Override
public long getItemId(int index) {
return index;
}
#Override
public View getView(int pos, View v, ViewGroup group) {
ParseUser c = getItem(pos);
if (v == null) {
v = layoutInflater.inflate(R.layout.chat_item, null);
}
labelname = (TextView) v;
labelname.setText(c.getUsername());
labelname.setCompoundDrawablesWithIntrinsicBounds(c.getBoolean("online") ? R.drawable.ic_online
: R.drawable.ic_offline, 0, R.drawable.arrow, 0);
return v;
}
}
I tried saveInBackground with SaveCallback, but it throws exception named:
Caused by: java.lang.IllegalArgumentException: Cannot save a ParseUser until it has been signed up. Call signUp first
But I'm puzzled more than I was 1 hour ago. I authorize my user in another class and it seems not to be problem.
This was open bug of Parse. might be possible that not solved yet. look at this and this too.
instead of saveEventually() use saveInBackground()
and
you can't do like that
ParseUser user = new ParseUser();
if you want logged user than get like this
ParseUser user = ParseUser.getCurrentUser();
and before getting logged user you must do sign up