what can be the reason that firebase gives databaseException error? I am new to android firebase adapter and I am facing an issue of databaseException. I was trying to get adapter in MainCommentFragment so I can use viewPager and recyclerview. But it seems like there is an error when I call mRecyclerView.setAdapter(mCommentAdapter); in MainCommentFragment.java. Can anyone help me with this?
Comment.java
public class Comment
{
public String uid;
public String username;
public String body;
public String time;
public String choice;
public int likeCount;
public int dislikeCount;
public Map<String, Boolean> likes = new HashMap<>();
public Map<String, Boolean> dislikes = new HashMap<>();
public Comment()
{
}
public Comment(String uid, String username, String body, String time, String choice)
{
this.uid = uid;
this.username = username;
this.body = body;
this.time = time;
this.choice = choice;
}
public Map<String, Object> toMap()
{
HashMap<String, Object> result = new HashMap<>();
result.put("uid", uid);
result.put("username", username);
result.put("time", time);
result.put("body", body);
result.put("likeCount", likeCount);
result.put("dislikeCount", dislikeCount);
result.put("likes", likes);
result.put("dislikes", dislikes);
result.put("choice", choice);
return result;
}
}
MainCommentFragment.java
public abstract class MainCommentFragment extends Fragment
{
/*UI*/
private RecyclerView mRecyclerView; //declaring recycler view
/*Firebase*/
private DatabaseReference mDatabase; //declaring database
/*Other*/
private FirebaseRecyclerAdapter<Comment, CommentViewHolder> mCommentAdapter; //declaring adapter for post
private LinearLayoutManager mLinearLayoutManager; //declaring linear layout manager
private String postKey;
/*Function*/
public MainCommentFragment() //creating a constructor for MainFragment
{
}
#Override
public View onCreateView (LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) //when view is created
{
super.onCreateView(inflater, container, savedInstanceState);
View rootView = inflater.inflate(R.layout.fragment_comment, container, false); //fragment_all_posts will invoked
mDatabase = FirebaseDatabase.getInstance().getReference(); //initializing database
mRecyclerView = (RecyclerView)rootView.findViewById(R.id.fragment_comment_recycler_view); //initializing recycler view
mRecyclerView.setHasFixedSize(true); //giving fixed size property to recycler view
RoomActivity roomActivity = (RoomActivity)getActivity();
postKey = roomActivity.getPostKey();
System.out.println("postKey=============================" + postKey);
return rootView; //returning view
}
#Override
public void onActivityCreated(Bundle savedInstanceState) //when activity is created
{
super.onActivityCreated(savedInstanceState);
mLinearLayoutManager = new LinearLayoutManager(getActivity()); //initializing linear layout manager
mLinearLayoutManager.setReverseLayout(true); //make the layout reverse
mLinearLayoutManager.setStackFromEnd(true); //make the layout stack from end
mRecyclerView.setLayoutManager(mLinearLayoutManager); //initialize recycler view
Query commentQuery = getQuery(mDatabase, postKey); //get query for database
mCommentAdapter = new FirebaseRecyclerAdapter<Comment, CommentViewHolder>(Comment.class, R.layout.comment_item, CommentViewHolder.class, commentQuery) //initializing post adapter
{
#Override
protected void populateViewHolder(CommentViewHolder viewHolder, Comment model, int position)
{
viewHolder.bindToComment(model, new View.OnClickListener()
{
#Override
public void onClick(View v)
{
DatabaseReference globalCommentRef = mDatabase.child("Comment").child(postKey);
onLikeClicked(globalCommentRef);
switch(v.getId())
{
case R.id.comment_item_like_btn:
onLikeClicked(globalCommentRef);
break;
case R.id.comment_item_dislike_btn:
onDislikeClicked(globalCommentRef);
break;
}
}
});
}
};
mRecyclerView.setAdapter(mCommentAdapter); //recycler view will not display post adapter
}
private void onLikeClicked(DatabaseReference commentRef)
{
commentRef.runTransaction(new Transaction.Handler()
{
#Override
public Transaction.Result doTransaction(MutableData mutableData)
{
Comment c = mutableData.getValue(Comment.class);
if(c == null)
{
return Transaction.success(mutableData);
}
if(c.likes.containsKey(FirebaseAuth.getInstance().getCurrentUser().getUid()))
{
} else
{
c.likeCount = c.likeCount + 1;
c.likes.put(FirebaseAuth.getInstance().getCurrentUser().getUid(), true);
if(c.dislikeCount != 0)
{
c.dislikeCount = c.dislikeCount - 1;
c.dislikes.remove(FirebaseAuth.getInstance().getCurrentUser().getUid());
}
}
mutableData.setValue(c);
return Transaction.success(mutableData);
}
#Override
public void onComplete(DatabaseError databaseError, boolean b, DataSnapshot dataSnapshot)
{
}
});
}
private void onDislikeClicked(DatabaseReference commentRef)
{
commentRef.runTransaction(new Transaction.Handler()
{
#Override
public Transaction.Result doTransaction(MutableData mutableData)
{
Comment c = mutableData.getValue(Comment.class);
if(c == null)
{
return Transaction.success(mutableData);
}
if(c.dislikes.containsKey(FirebaseAuth.getInstance().getCurrentUser().getUid()))
{
} else
{
c.dislikeCount = c.dislikeCount + 1;
c.dislikes.put(FirebaseAuth.getInstance().getCurrentUser().getUid(), true);
if(c.likeCount != 0)
{
c.likeCount = c.likeCount - 1;
c.likes.remove(FirebaseAuth.getInstance().getCurrentUser().getUid());
}
}
mutableData.setValue(c);
return Transaction.success(mutableData);
}
#Override
public void onComplete(DatabaseError databaseError, boolean b, DataSnapshot dataSnapshot)
{
}
});
}
public abstract Query getQuery(DatabaseReference databaseReference, String postKey); //declaring query
}
This is the error message.
com.google.firebase.database.DatabaseException: Can't convert object of type java.lang.Long to type packagename.Comment
Related
I'm trying to make a comment system for posts on my social media app. In my database each post has a section inside of "comments" table, like so:
"hypno--######" is the title of the social media post. It Contains the comment, user id of the user who posted the comment, and a unixtimestamp when the comment was posted. Each comment is titled after the time it was posted.
This is the Comment class
public class comment {
public String uID;
public String comment_t;
public long unixTimestamp;
public comment() {
// Default constructor required for calls to DataSnapshot.getValue(User.class)
}
public comment(String uID, String comment_t, long unixTimestamp) {
this.uID = uID;
this.comment_t = comment_t;
this.unixTimestamp = unixTimestamp;
}
public String getuID() {
return uID;
}
public void setuID(String uID) {
this.uID = uID;
}
public String getComment() {return comment_t;}
public void setComment() {this.comment_t = comment_t; }
public long getUnixTimestamp() {
return unixTimestamp;
}
}
This is the Comment Adapter:
Public class Adapter_Comment extends FirebaseRecyclerAdapter<comment, Adapter_Comment.ViewHolder_com> {
private DatabaseReference mDatabase;
private static final String TAG = "RecyclerViewAdapter";
private Context mContext;
FirebaseUser user = FirebaseAuth.getInstance().getCurrentUser();
private static AppCompatActivity unwrap(Context context) {
while (!(context instanceof Activity) && context instanceof ContextWrapper) {
context = ((ContextWrapper) context).getBaseContext();
}
return (AppCompatActivity) context;
}
public Adapter_Comment(#NonNull FirebaseRecyclerOptions<comment> options) {
super(options);
//this.mContext = mContext;
}
#NonNull
#Override
public ViewHolder_com onCreateViewHolder(#NonNull ViewGroup parent, int viewType) {
View view = LayoutInflater.from(parent.getContext()).inflate(R.layout.layout_comment, parent, false);
mDatabase = FirebaseDatabase.getInstance().getReference();
return new ViewHolder_com(view);
}
#Override
protected void onBindViewHolder(#NonNull ViewHolder_com holder, int position, #NonNull comment model) {
mDatabase = FirebaseDatabase.getInstance().getReference();
long dv = model.getUnixTimestamp()*-1000;
Date df = new java.util.Date(dv);
String vv = new SimpleDateFormat("MM dd, yyyy hh:mma", Locale.ENGLISH).format(df);
holder.time.setText(vv);
String com = model.getComment();
holder.comment_text.setText(com);
mDatabase.child("users").child(model.getuID()).child("profileUrl").addListenerForSingleValueEvent(new ValueEventListener() {
#Override
public void onDataChange(#NonNull DataSnapshot snapshot) {
if (snapshot.exists())
{
final String picUrl = snapshot.getValue(String.class);
Glide.with(holder.postPfp.getContext()).load(picUrl).into(holder.postPfp);
}
}
#Override
public void onCancelled(#NonNull DatabaseError error) { }
});
holder.postPfp.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
//AppCompatActivity activity = (AppCompatActivity) v.getContext();
AppCompatActivity activity = unwrap(v.getContext());
Fragment OtherProfileFragment = new OtherProfileFragment();
Bundle bundle = new Bundle();
bundle.putString("key", model.getuID());
OtherProfileFragment.setArguments(bundle);
activity.getSupportFragmentManager().beginTransaction().replace(R.id.fragment_container, OtherProfileFragment).addToBackStack(null).commit();
}
});
}
public class ViewHolder_com extends RecyclerView.ViewHolder {
TextView comment_text;
CircleImageView postPfp;
TextView time;
RelativeLayout comment_layout;
public ViewHolder_com(#NonNull View itemView) {
super(itemView);
postPfp = itemView.findViewById(R.id.iv_comment_icon);
comment_text = itemView.findViewById(R.id.tv_comment_text);
time = itemView.findViewById(R.id.tv_comment_time);
comment_layout = itemView.findViewById(R.id.comment_layout);
}
}
}
This is Comment Fragment:
public class CommentFragment extends Fragment {
private DatabaseReference mDatabase;
FirebaseUser user = FirebaseAuth.getInstance().getCurrentUser();
View view;
String value;
RecyclerView recyclerView;
Query query;
TextView comment_text;
long unixTime = System.currentTimeMillis() / 1000L;
public long globalUnix;
Button comment_post;
String comment_string;
Adapter_Comment adapter;
#Nullable
#Override
public View onCreateView(#NonNull LayoutInflater inflater, #Nullable ViewGroup container, #Nullable Bundle savedInstanceState) {
view = inflater.inflate(R.layout.fragment_comment, container, false);
value = getArguments().getString("key");
mDatabase = FirebaseDatabase.getInstance().getReference();
recyclerView = view.findViewById(R.id.recyclerv_comment);
comment_text = view.findViewById(R.id.tv_comment_type);
comment_post = view.findViewById(R.id.btn_comment_post);
globalUnix = (unixTime * -1);
comment_post.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
if(comment_text.getText().toString() == NULL){
Toast.makeText(getActivity(), "No Comment Typed", Toast.LENGTH_LONG).show();
}
else{
comment com = new comment();
com.uID = user.getUid();
com.comment_t = comment_text.getText().toString();
com.unixTimestamp = globalUnix;
mDatabase.child("comments").child(value).child(globalUnix + "").setValue(com);
}
}
});
initRecyclerView();
return view;
}
private void initRecyclerView(){
//Log.d(TAG, "initRecyclerView: init recyclerView");
LinearLayoutManager layoutManager = new LinearLayoutManager(getContext());
recyclerView.setLayoutManager(layoutManager);
query = FirebaseDatabase.getInstance().getReference().child("comments").orderByValue();
FirebaseRecyclerOptions<comment> options = new FirebaseRecyclerOptions.Builder<comment>().setQuery(query, comment.class).build();
adapter = new Adapter_Comment(options);
recyclerView.setAdapter(adapter);
adapter.startListening();
adapter.notifyDataSetChanged();
}
#Override
public void onCreate(#Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
}
}
Inside of the adapter I'm using the comment model, to get the uID, comment and timestamp to fill the holder, however when i set these values im getting null values. Is there something im missing when trying to connect the adapter/firebase and model/holder?
long dv = model.getUnixTimestamp()*-1000;
Date df = new java.util.Date(dv);
String vv = new SimpleDateFormat("MM dd, yyyy hh:mma", Locale.ENGLISH).format(df);
holder.time.setText(vv);
String com = model.getComment();
holder.comment_text.setText(com);
mDatabase.child("users").child(model.getuID()).child("profileUrl").addListenerForSingleValueEvent(new ValueEventListener() {
#Override
public void onDataChange(#NonNull DataSnapshot snapshot) {
if (snapshot.exists())
{
final String picUrl = snapshot.getValue(String.class);
Glide.with(holder.postPfp.getContext()).load(picUrl).into(holder.postPfp);
}
}
#Override
public void onCancelled(#NonNull DatabaseError error) { }
});
There's really too much going on in here, but...
As far as I can see you're creating a FirebaseUI adapter on FirebaseDatabase.getInstance().getReference().child("comments"). FirebaseUI adapters show the direct child nodes of the node you pass in, so in your case it'll create one view for the hypno---...196 node. You're trying to read a Comment object from there, but don't exist until one level lower in your JSON.
So you can:
Either show the comments for one post, by basing the adapter off of that. So: FirebaseDatabase.getInstance().getReference().child("comments").child("hypno---...196") (which the real key in there).
Or you can show one piece of information about each post, for example its key.
If you want to show a flat list of comments for all posts through the FirebaseUI adapter, you'll have to store a flat list of comments across all posts in your database too.
I used Firebase Firestore to create a realtime recycler view with pagination, but the problem is that I am trying to order the documents using Timestamp. When I try to add a new document the app crashes. This only happens when adding the first document in a collection, after that it will work fine.
This is the error I'm getting:
java.lang.IllegalArgumentException: Invalid query. You are trying to start or end a query using a document for which the field 'date_posted' is an uncommitted server timestamp. (Since the value of this field is unknown, you cannot start/end a query with it.)
at com.google.firebase.firestore.Query.boundFromDocumentSnapshot(com.google.firebase:firebase-firestore##21.4.3:758)
at com.google.firebase.firestore.Query.startAfter(com.google.firebase:firebase-firestore##21.4.3:648)
at com.project.alihammoud.foodreviewlb.BottomSheetFragmentComment.loadMore(BottomSheetFragmentComment.java:251)
at com.project.alihammoud.foodreviewlb.BottomSheetFragmentComment$2.onScrolled(BottomSheetFragmentComment.java:191)
at androidx.recyclerview.widget.RecyclerView.dispatchOnScrolled(RecyclerView.java:5173)
I have it that when I send a document to the firestore database, it gets its timestamp from the firestore server. I know that there is a delay in assigning the Timestamp so I tried adding a wait before refreshing but that did not work. Any ideas what could work to avoid this issue?
Here is my code:
public class BottomSheetFragmentComment extends BottomSheetDialogFragment {
private Toolbar toolbar;
private String document_id;
private String currentUserID;
private FirebaseAuth auth;
private FirebaseUser currentUser;
private FirebaseFirestore db;
private RecyclerView recyclerView;
private List<CommentInfo> comments_list;
private CommentsAdapter commentsAdapter;
private ImageButton comment_button;
private EditText comment_text;
private DocumentSnapshot lastVisible;
private Boolean isFirstPageFirstLoad = true;
private CommentID commentID;
public BottomSheetFragmentComment(){
}
#Nullable
#Override
public View onCreateView(#NonNull LayoutInflater inflater, #Nullable ViewGroup container, #Nullable Bundle savedInstanceState) {
View view = inflater.inflate(R.layout.bottom_sheet_comments,container,false);
document_id = this.getArguments().getString("docID");
auth = FirebaseAuth.getInstance();
currentUser = auth.getCurrentUser();
currentUserID = currentUser.getUid();
db = FirebaseFirestore.getInstance();
comments_list = new ArrayList<>();
commentsAdapter = new CommentsAdapter(comments_list);
Query firstQuery = db.collection("Reviews").document(document_id).collection("Comments")
.orderBy("date_posted", Query.Direction.DESCENDING)
.limit(20);
firstQuery.addSnapshotListener(new EventListener<QuerySnapshot>() {
#Override
public void onEvent(#Nullable QuerySnapshot documentSnapshot, #Nullable FirebaseFirestoreException e) {
if (e == null){
if (!documentSnapshot.isEmpty()){
if (isFirstPageFirstLoad){
lastVisible = documentSnapshot.getDocuments().get(documentSnapshot.size()-1);
}
for (DocumentChange documentChange: documentSnapshot.getDocumentChanges()){
if (documentChange.getType() == DocumentChange.Type.ADDED){
String commentID = documentChange.getDocument().getId();
CommentInfo commentAdded = documentChange.getDocument().toObject(CommentInfo.class);
if (isFirstPageFirstLoad){
comments_list.add(commentAdded);
}
else {
comments_list.add(0,commentAdded);
}
commentsAdapter.notifyDataSetChanged();
}
else if (documentChange.getType() == DocumentChange.Type.REMOVED){
comments_list.remove(documentChange.getOldIndex());
commentsAdapter.notifyItemRemoved(documentChange.getOldIndex());
}
else if (documentChange.getType() == DocumentChange.Type.MODIFIED){
CommentInfo commentModified = documentChange.getDocument().toObject(CommentInfo.class);
if (documentChange.getOldIndex() == documentChange.getNewIndex()) {
// Item changed but remained in same position
comments_list.set(documentChange.getOldIndex(),commentModified);
commentsAdapter.notifyItemChanged(documentChange.getOldIndex());
}else {
// Item changed and changed position
comments_list.remove(documentChange.getOldIndex());
comments_list.add(documentChange.getNewIndex(),commentModified);
commentsAdapter.notifyItemMoved(documentChange.getOldIndex(),documentChange.getNewIndex());
}
commentsAdapter.notifyDataSetChanged();
}
}
isFirstPageFirstLoad = false;
}
}
}
});
// db.collection("Reviews").document(document_id).collection("Comments")
if (currentUser != null){
//setUpRecyclerView();
recyclerView = view.findViewById(R.id.recycle_view);
recyclerView.setHasFixedSize(true);
LinearLayoutManager mLayoutManager = new LinearLayoutManager(getContext());
mLayoutManager.setReverseLayout(true);
// mLayoutManager.setStackFromEnd(true);
recyclerView.setLayoutManager(mLayoutManager);
recyclerView.setAdapter(commentsAdapter);
recyclerView.addOnScrollListener(new RecyclerView.OnScrollListener() {
#Override
public void onScrollStateChanged(#NonNull RecyclerView recyclerView, int newState) {
super.onScrollStateChanged(recyclerView, newState);
}
#Override
public void onScrolled(#NonNull RecyclerView recyclerView, int dx, int dy) {
super.onScrolled(recyclerView, dx, dy);
Boolean reachedBottom = !recyclerView.canScrollVertically(-5);
if (reachedBottom){
String desc = lastVisible.getString("comment");
Toast.makeText(getContext(),"Reached: " + desc ,Toast.LENGTH_SHORT).show();
loadMore();
/* final Handler handler = new Handler();
handler.postDelayed(new Runnable() {
#Override
public void run() {
}
},5000);*/
}
}
});
}
toolbar = view.findViewById(R.id.toolbar);
toolbar.setTitle("Comments");
toolbar.setTitleTextColor(Color.BLACK);
comment_text = view.findViewById(R.id.comment_text);
comment_button = view.findViewById(R.id.comment_button);
comment_button.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
db.collection("Reviews").document(document_id).get().addOnCompleteListener(new OnCompleteListener<DocumentSnapshot>() {
#Override
public void onComplete(#NonNull Task<DocumentSnapshot> task) {
if (task.getResult().exists()){
DocumentReference newComment = db.collection("Reviews").document(document_id).collection("Comments").document();
CommentInfo commentInfo = new CommentInfo();
commentInfo.setUser_id(currentUserID);
commentInfo.setComment(comment_text.getText().toString().trim());
newComment.set(commentInfo);
comment_text.getText().clear();
}
else {
Toast.makeText(getContext(), "This review has been removed, please refresh your feed.", Toast.LENGTH_LONG).show();
}
}
});
}
});
return view;
}
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
}
public void loadMore(){
Query nextQuery = db.collection("Reviews").document(document_id).collection("Comments")
.orderBy("date_posted", Query.Direction.DESCENDING)
.startAfter(lastVisible)
.limit(10);
nextQuery.addSnapshotListener(new EventListener<QuerySnapshot>() {
#Override
public void onEvent(#Nullable QuerySnapshot documentSnapshot, #Nullable FirebaseFirestoreException e) {
if (e == null){
if (!documentSnapshot.isEmpty()){
lastVisible = documentSnapshot.getDocuments().get(documentSnapshot.size()-1);
for (DocumentChange documentChange: documentSnapshot.getDocumentChanges()){
if (documentChange.getType() == DocumentChange.Type.ADDED){
String commentID = documentChange.getDocument().getId();
CommentInfo commentAdded = documentChange.getDocument().toObject(CommentInfo.class);
comments_list.add(commentAdded);
commentsAdapter.notifyDataSetChanged();
}
else if (documentChange.getType() == DocumentChange.Type.REMOVED){
comments_list.remove(documentChange.getOldIndex());
commentsAdapter.notifyItemRemoved(documentChange.getOldIndex());
}
else if (documentChange.getType() == DocumentChange.Type.MODIFIED){
// modifying
CommentInfo commentModified = documentChange.getDocument().toObject(CommentInfo.class);
if (documentChange.getOldIndex() == documentChange.getNewIndex()) {
// Item changed but remained in same position
comments_list.set(documentChange.getOldIndex(),commentModified);
commentsAdapter.notifyItemChanged(documentChange.getOldIndex());
}else {
// Item changed and changed position
comments_list.remove(documentChange.getOldIndex());
comments_list.add(documentChange.getNewIndex(),commentModified);
commentsAdapter.notifyItemMoved(documentChange.getOldIndex(),documentChange.getNewIndex());
}
commentsAdapter.notifyDataSetChanged();
}
}
}
}
}
});
}
#NonNull #Override public Dialog onCreateDialog(Bundle savedInstanceState) {
Dialog dialog = super.onCreateDialog(savedInstanceState);
dialog.setOnShowListener(new DialogInterface.OnShowListener() {
#Override public void onShow(DialogInterface dialogInterface) {
BottomSheetDialog bottomSheetDialog = (BottomSheetDialog) dialogInterface;
setupFullHeight(bottomSheetDialog);
}
});
return dialog;
}
private void setupFullHeight(BottomSheetDialog bottomSheetDialog) {
FrameLayout bottomSheet = (FrameLayout) bottomSheetDialog.findViewById(R.id.design_bottom_sheet);
BottomSheetBehavior behavior = BottomSheetBehavior.from(bottomSheet);
ViewGroup.LayoutParams layoutParams = bottomSheet.getLayoutParams();
int windowHeight = getWindowHeight();
if (layoutParams != null) {
layoutParams.height = windowHeight;
}
bottomSheet.setLayoutParams(layoutParams);
behavior.setState(BottomSheetBehavior.STATE_EXPANDED);
}
private int getWindowHeight() {
// Calculate window height for fullscreen use
DisplayMetrics displayMetrics = new DisplayMetrics();
((Activity) getContext()).getWindowManager().getDefaultDisplay().getMetrics(displayMetrics);
return displayMetrics.heightPixels;
}
}
public class CommentsAdapter extends RecyclerView.Adapter<CommentsAdapter.ViewHolder> {
private Context context;
private FirebaseFirestore db;
public List<CommentInfo> comments_list;
public CommentsAdapter(List<CommentInfo> comments_list){
this.comments_list = comments_list;
}
#NonNull
#Override
public ViewHolder onCreateViewHolder(#NonNull ViewGroup parent, int viewType) {
View v = LayoutInflater.from(parent.getContext()).inflate(R.layout.card_view_comments,parent,false);
context = parent.getContext();
return new ViewHolder(v);
}
#Override
public void onBindViewHolder(#NonNull final ViewHolder holder, int position) {
db = FirebaseFirestore.getInstance();
//final String commentID = comments_list.get(position)
String comment = comments_list.get(position).getComment();
holder.setComment(comment);
final String commentUserID = comments_list.get(position).getUser_id();
DocumentReference userData = db.collection("Users").document(commentUserID);
userData.get().addOnCompleteListener(new OnCompleteListener<DocumentSnapshot>() {
#Override
public void onComplete(#NonNull Task<DocumentSnapshot> task) {
if (task.isSuccessful()) {
if (task.getResult().exists()) {
String firstname = task.getResult().getString("first_name");
String lastname = task.getResult().getString("last_name");
String userPicture = task.getResult().getString("profile_picture");
holder.setUserData(firstname,lastname,userPicture);
}
}
}
});
}
#Override
public int getItemCount() {
return comments_list.size();
}
public class ViewHolder extends RecyclerView.ViewHolder{
private View mView;
private TextView comment, first_name, last_name;
CircleImageView users_profile_picture;
public ViewHolder(#NonNull final View itemView) {
super(itemView);
mView = itemView;
}
public void setComment(String CommentText){
comment = mView.findViewById(R.id.comment);
comment.setText(CommentText);
}
private void setUserData(String firstName, String lastName, String profilePicture){
first_name = mView.findViewById(R.id.first_name);
last_name = mView.findViewById(R.id.last_name);
users_profile_picture = mView.findViewById(R.id.users_profile_picture);
first_name.setText(firstName);
last_name.setText(lastName);
if (profilePicture != null){
Glide.with(context).load(profilePicture).into(users_profile_picture);
}
}
}
}
#IgnoreExtraProperties
public class CommentInfo {
private String user_id;
private String comment;
private #ServerTimestamp Date date_posted;
public CommentInfo(){
}
public CommentInfo(String user_id, String comment, Date date_posted) {
this.user_id = user_id;
this.comment = comment;
this.date_posted = date_posted;
}
public String getUser_id() {
return user_id;
}
public void setUser_id(String user_id) {
this.user_id = user_id;
}
public String getComment() {
return comment;
}
public void setComment(String comment) {
this.comment = comment;
}
public Date getDate_posted() {
return date_posted;
}
public void setDate_posted(Date date_posted) {
this.date_posted = date_posted;
}
}
The error message is:
Invalid query. You are trying to start or end a query using a document for which the field 'date_posted' is an uncommitted server timestamp. (Since the value of this field is unknown, you cannot start/end a query with it.)
So it looks like it comes from this:
Query nextQuery = db.collection("Reviews").document(document_id).collection("Comments")
.orderBy("date_posted", Query.Direction.DESCENDING)
.startAfter(lastVisible)
.limit(10);
From the error message it seems that the date_posted field may have unknown values, in which case you can't query on it.
This comes from:
private #ServerTimestamp Date date_posted;
From this Github issue with multiple comments from Firestore team members, it seems that:
pagination and server-issued time are essentially incompatible
I am making an application in which I am saving data on one page that is RequestOrder on Firebase Realtime Database and I want to retrieve it on other page that is PendingOrder.
I am using tablayouts with fragment one tab showing PendingOrder and the one showing completed order. After Googling a lot I have come to the point that everyone is using ListView to retrieve data from Firebase.
I try to do the same but am stuck in an error. Please help me out.
The error is "java.lang.NullPointerException: Attempt to invoke virtual method 'java.lang.String com.example.hp.another.ServiceConsumer.getPkgDetail()' on a null object reference"
public class PendingOrder extends Fragment {
DatabaseReference databaseReference;
FirebaseDatabase firebaseDatabase;
FirebaseAuth.AuthStateListener mAuthListener;
ListView listView1;
String userId;
List<ServiceConsumer> consumerList;
private static final String TAG = "PendingOrder";
#Nullable
#Override
public View onCreateView(#NonNull LayoutInflater inflater, #Nullable ViewGroup container, #Nullable Bundle savedInstanceState) {
View RootView= inflater.inflate(R.layout.pendingorders, container, false);
listView1 = (ListView) RootView.findViewById(R.id.listview);
return RootView;
}
#Override
public void onCreate(#Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
FirebaseAuth firebaseAuth = FirebaseAuth.getInstance();
firebaseDatabase = FirebaseDatabase.getInstance();
databaseReference = FirebaseDatabase.getInstance().getReference();
FirebaseUser user = firebaseAuth.getCurrentUser();
userId = user.getUid();
}
#Override
public void onStart() {
super.onStart();
databaseReference.addValueEventListener(new ValueEventListener() {
#Override
public void onDataChange(DataSnapshot dataSnapshot) {
showData(dataSnapshot);
}
#Override
public void onCancelled(DatabaseError databaseError) {
}
});
}
private void showData(DataSnapshot dataSnapshot) {
for (DataSnapshot ds : dataSnapshot.getChildren()) {
ServiceConsumer uInfo = new ServiceConsumer();
uInfo.setPkgDetail(ds.child(userId).getValue(ServiceConsumer.class).getPkgDetail());
uInfo.setPkgWeight(ds.child(userId).getValue(ServiceConsumer.class).getPkgWeight());
uInfo.setPersonContct(ds.child(userId).getValue(ServiceConsumer.class).getPersonContct());
uInfo.setPickupAddrs(ds.child(userId).getValue(ServiceConsumer.class).getPickupAddrs());
uInfo.setConsumerName(ds.child(userId).getValue(ServiceConsumer.class).getConsumerName());
uInfo.setConsumerPhone(ds.child(userId).getValue(ServiceConsumer.class).getConsumerPhone());
uInfo.setConsumerAddres(ds.child(userId).getValue(ServiceConsumer.class).getConsumerAddres());
Log.d(TAG, "showData:pkgdetail:" + uInfo.getPkgDetail());
Log.d(TAG, "showData:pkgweight:" + uInfo.getPkgWeight());
Log.d(TAG, "showData:persncntct:"+uInfo.getPersonContct());
Log.d(TAG, "showData:pickup:"+uInfo.getPickupAddrs());
Log.d(TAG, "showData:cnname:"+uInfo.getConsumerName());
Log.d(TAG, "showData:cnphone:"+uInfo.getConsumerPhone());
Log.d(TAG, "showData:cnadd:"+uInfo.getConsumerAddres());
ArrayList<String>array= new ArrayList<>();
array.add(uInfo.getPkgDetail());
array.add(uInfo.getPkgWeight());
array.add(uInfo.getPersonContct());
array.add(uInfo.getPickupAddrs());
array.add(uInfo.getConsumerName());
array.add(uInfo.getConsumerAddres());
array.add(uInfo.getConsumerPhone());
ArrayAdapter<String> adapter= new ArrayAdapter<String>(getActivity(),android.R.layout.simple_list_item_1,array);
listView1.setAdapter(adapter);
}
}
ServiceConsumer class
public class ServiceConsumer {
private String Id;
private String PkgDetail;
private String PkgWeight;
private String PersonContct;
private String PickupAddrs;
private String ConsumerName;
private String ConsumerPhone;
private String ConsumerAddres;
public ServiceConsumer() {
}
public ServiceConsumer(String id, String pkgdetail, String pkgweight, String personContct, String add, String consumerName, String consumerPhone, String consumerAdd) {
Id= id;
PkgDetail = pkgdetail;
PkgWeight = pkgweight;
PersonContct = personContct;
PickupAddrs = add;
ConsumerName = consumerName;
ConsumerPhone = consumerPhone;
ConsumerAddres = consumerAdd;
}
public String getId() {
return Id;
}
public String getPkgDetail() {
return PkgDetail;
}
public String getPkgWeight() {
return PkgWeight;
}
public String getPersonContct() {
return PersonContct;
}
public String getPickupAddrs() {
return PickupAddrs;
}
public String getConsumerName() {
return ConsumerName;
}
public String getConsumerPhone() {
return ConsumerPhone;
}
public String getConsumerAddres() {
return ConsumerAddres;
}
public void setId(String id) {
Id = id;
}
public void setPkgDetail(String pkgDetail) {
PkgDetail = pkgDetail;
}
public void setPkgWeight(String pkgWeight) {
PkgWeight = pkgWeight;
}
public void setPersonContct(String personContct) {
PersonContct = personContct;
}
public void setPickupAddrs(String pickupAddrs) {
PickupAddrs = pickupAddrs;
}
public void setConsumerName(String consumerName) {
ConsumerName = consumerName;
}
public void setConsumerPhone(String consumerPhone) {
ConsumerPhone = consumerPhone;
}
public void setConsumerAddres(String consumerAddres) {
ConsumerAddres = consumerAddres;
}
}
Try to make PkgDetail NonNull or save an empty string to it.
private String PkgDetail = "" ;
This is SearchActivity.java
public class SearchActivity extends AppCompatActivity
{
/*UI*/
private EditText mSearchText;
private Button mSearchBtn;
private Toolbar mSearchToolbar;
private FragmentPagerAdapter mPagerAdapter;
private ViewPager mViewPager;
private String value;
private TextWatcher tw;
#Override
protected void onCreate(Bundle savedInstanceState)
{
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_search);
mSearchText = (EditText)findViewById(R.id.activity_search_search_text);
mSearchBtn = (Button)findViewById(R.id.activity_search_search_btn);
mSearchToolbar = (Toolbar)findViewById(R.id.activity_search_toolbar);
setSupportActionBar(mSearchToolbar);
getSupportActionBar().setDisplayHomeAsUpEnabled(true);
getSupportActionBar().setTitle(null);
mSearchBtn.setOnClickListener(new View.OnClickListener()
{
#Override
public void onClick(View v)
{
value = mSearchText.getText().toString();
Toast.makeText(SearchActivity.this, "value test 1: " + value, Toast.LENGTH_LONG).show();
searchText(value);
}
});
}
private void searchText(final String value)
{
Toast.makeText(SearchActivity.this, "value test 2: " + value, Toast.LENGTH_LONG).show();
mPagerAdapter = new FragmentPagerAdapter(getSupportFragmentManager())
{
private final Fragment[] mFragments = new Fragment[]
{
new FragmentSearch(value)
};
#Override
public Fragment getItem(int position)
{
return mFragments[position];
}
#Override
public int getCount()
{
return mFragments.length;
}
};
mViewPager = (ViewPager) findViewById(R.id.activity_search_view_pager);
mViewPager.setAdapter(mPagerAdapter);
}
}
This is FragmentSearch.java
public class FragmentSearch extends MainFragment
{
public String value;
public FragmentSearch(String value)
{
this.value = value;
}
#Override
public Query getQuery(DatabaseReference databaseReference)
{
Toast.makeText(getActivity().this, "value test 3: " + value, Toast.LENGTH_LONG).show();
Query postsQuery = databaseReference.child("Post").orderByChild("title").equalTo(value);
return postsQuery;
}
}
This is MainFragment.java
public abstract class MainFragment extends Fragment
{
private DatabaseReference mDatabase;
private FirebaseRecyclerAdapter<Post, PostViewHolder> mAdapter;
private RecyclerView mRecycler;
private LinearLayoutManager mManager;
public MainFragment()
{
}
#Override
public View onCreateView (LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState)
{
super.onCreateView(inflater, container, savedInstanceState);
View rootView = inflater.inflate(R.layout.fragment_all_posts, container, false);
mDatabase = FirebaseDatabase.getInstance().getReference();
mRecycler = (RecyclerView)rootView.findViewById(R.id.messages_list);
mRecycler.setHasFixedSize(true);
return rootView;
}
#Override
public void onActivityCreated(Bundle savedInstanceState)
{
super.onActivityCreated(savedInstanceState);
mManager = new LinearLayoutManager(getActivity());
mManager.setReverseLayout(true);
mManager.setStackFromEnd(true);
mRecycler.setLayoutManager(mManager);
Query postsQuery = getQuery(mDatabase);
mAdapter = new FirebaseRecyclerAdapter<Post, PostViewHolder>(Post.class, R.layout.item_post,
PostViewHolder.class, postsQuery)
{
#Override
protected void populateViewHolder(final PostViewHolder viewHolder, final Post model, final int position)
{
final DatabaseReference postRef = getRef(position);
final String postKey = postRef.getKey();
viewHolder.itemView.setOnClickListener(new View.OnClickListener()
{
#Override
public void onClick(View v)
{
// Intent intent = new Intent(getActivity(), PostDetailActivity.class);
// intent.putExtra(PostDetailActivity.EXTRA_POST_KEY, postKey);
// startActivity(intent);
}
});
if(model.stars.containsKey(getUid()))
{
viewHolder.starView.setImageResource(R.drawable.ic_toggle_star_24);
}
else
{
viewHolder.starView.setImageResource(R.drawable.ic_toggle_star_outline_24);
}
viewHolder.bindToPost(model, new View.OnClickListener()
{
#Override
public void onClick(View starView)
{
DatabaseReference globalPostRef = mDatabase.child("Post").child(postRef.getKey());
DatabaseReference userPostRef = mDatabase.child("UserPost").child(model.uid).child(postRef.getKey());
onStarClicked(globalPostRef);
onStarClicked(userPostRef);
}
});
}
};
mRecycler.setAdapter(mAdapter);
}
private void onStarClicked(DatabaseReference postRef) {
postRef.runTransaction(new Transaction.Handler() {
#Override
public Transaction.Result doTransaction(MutableData mutableData) {
Post p = mutableData.getValue(Post.class);
if (p == null) {
return Transaction.success(mutableData);
}
if (p.stars.containsKey(getUid())) {
// Unstar the post and remove self from stars
p.starCount = p.starCount - 1;
p.stars.remove(getUid());
} else {
// Star the post and add self to stars
p.starCount = p.starCount + 1;
p.stars.put(getUid(), true);
}
// Set value and report transaction success
mutableData.setValue(p);
return Transaction.success(mutableData);
}
#Override
public void onComplete(DatabaseError databaseError, boolean b,
DataSnapshot dataSnapshot) {
}
});
}
#Override
public void onDestroy()
{
super.onDestroy();
if (mAdapter != null)
{
mAdapter.cleanup();
}
}
public String getUid()
{
return FirebaseAuth.getInstance().getCurrentUser().getUid();
}
public abstract Query getQuery(DatabaseReference databaseReference);
}
This is PostViewHolder.java
public class PostViewHolder extends RecyclerView.ViewHolder
{
public TextView titleView;
public TextView authorView;
public ImageView starView;
public TextView numStarsView;
public TextView bodyView;
public PostViewHolder(View itemView)
{
super(itemView);
titleView = (TextView) itemView.findViewById(R.id.post_title);
authorView = (TextView) itemView.findViewById(R.id.post_author);
starView = (ImageView) itemView.findViewById(R.id.star);
numStarsView = (TextView) itemView.findViewById(R.id.post_num_stars);
bodyView = (TextView) itemView.findViewById(R.id.post_body);
}
public void bindToPost(Post post, View.OnClickListener starClickListener)
{
titleView.setText(post.title);
authorView.setText(post.author);
numStarsView.setText(String.valueOf(post.starCount));
bodyView.setText(post.body);
starView.setOnClickListener(starClickListener);
}
}
This is Post.java
#IgnoreExtraProperties
public class Post
{
public String uid;
public String author;
public String title;
public String body;
public int starCount = 0;
public String type;
public Map<String, Boolean> stars = new HashMap<>();
public Post()
{
}
public Post(String uid, String author, String title, String body, String type)
{
this.uid = uid;
this.author = author;
this.title = title;
this.body = body;
this.type = type;
}
#Exclude
public Map<String, Object> toMap()
{
HashMap<String, Object> result = new HashMap<>();
result.put("uid", uid);
result.put("author", author);
result.put("title", title);
result.put("body", body);
result.put("starCount", starCount);
result.put("stars", stars);
result.put("type", type);
return result;
}
}
Thank you so much for reading. I created a program to search title of the posts. When I type title in the EditText then press Search button, my toast1 test, toast2 test, and toast3 test give correct and same value and it successfully lists what I want with Query. But the problem is that when I type different text in EditText after deleting the previous text then press enter, toast3 test(in FragmentSearch.java) stays the same and does not change value. So, it just gives the previous result, not changed result. Can anyone assist me with this? Thank you!
The problem is that you only change the value on the FragmentSearch constructor. And this constructor is only called once, and not when you press Enter.
You should change your getQuery method to have this value as a parameter.
On your MainFragment.java:
public abstract Query getQuery(DatabaseReference databaseReference, String value);
On your FragmentSearch.java:
#Override
public Query getQuery(DatabaseReference databaseReference, String value)
{
this.value = value;
Toast.makeText(getActivity().this, "value test 3: " + value, Toast.LENGTH_LONG).show();
Query postsQuery = databaseReference.child("Post").orderByChild("title").equalTo(value);
return postsQuery;
}
The data is being fetched in the fetchData() method in FirebaseHelper, but isn't actually being stored in the variables petInfo and imgURL in the CardViewAdapter. This results in no cards showing in the RecyclerView fragment. When the app initializes, the dataset is 0, runs through the fetchData and the dataset is the size of items but leaves petInfo and imgURL null.
FirebaseHelper:
public class FirebaseHelper {
private DatabaseReference mDatabase;
Boolean saved = null;
ArrayList<AnimalType> animal = new ArrayList<>();
public FirebaseHelper(DatabaseReference mDatabase) {
this.mDatabase = mDatabase;
}
//Save
public Boolean save (AnimalType animalType){
if (animalType==null){
saved = false;
}
else{
try{
mDatabase.child("AnimalType").push().setValue(animalType);
saved=true;
}catch (DatabaseException e){
e.printStackTrace();
saved=false;
}
}
return saved;
}
//Read
public ArrayList<AnimalType> retrieve(){
mDatabase.addChildEventListener(new ChildEventListener() {
#Override
public void onChildAdded(DataSnapshot dataSnapshot, String s) {
fetchData(dataSnapshot);
Log.i(TAG, "onChildAdded");
}
#Override
public void onChildChanged(DataSnapshot dataSnapshot, String s) {
fetchData(dataSnapshot);
Log.i(TAG, "onChildChanged");
}
#Override
public void onChildRemoved(DataSnapshot dataSnapshot) {
}
#Override
public void onChildMoved(DataSnapshot dataSnapshot, String s) {
}
#Override
public void onCancelled(DatabaseError databaseError) {
}
});
return animal;
}
private void fetchData (DataSnapshot dataSnapshot){
animal.clear();
for (DataSnapshot ds : dataSnapshot.getChildren()){
AnimalType animalType = new AnimalType();
animalType.setPetInfo(ds.getValue(AnimalType.class).getPetInfo());
animalType.setImgURL(ds.getValue(AnimalType.class).getImgURL());
animal.add(animalType);
}
}
}
Adapter:
public class CardViewAdapter extends RecyclerView.Adapter<CardViewAdapter.ViewHolder> {
Context mContext;
private List<AnimalType> mAnimalData = new ArrayList<>();
public class ViewHolder extends RecyclerView.ViewHolder {
public TextView petInfo;
public ImageView imgURL;
public ViewHolder(View view){
super(view);
imgURL = (ImageView) view.findViewById(R.id.pet_image);
petInfo = (TextView) view.findViewById(R.id.pet_description);
}
}
//constructor
public CardViewAdapter(Context mContext, List<AnimalType> mAnimalData){
this.mAnimalData = mAnimalData;
}
//create new views
#Override
public CardViewAdapter.ViewHolder onCreateViewHolder(ViewGroup parent, int viewType){
View itemView = LayoutInflater.from(parent.getContext()).inflate(R.layout.row_layout, parent, false);
ViewHolder viewHolder = new ViewHolder(itemView);
mContext = parent.getContext();
return viewHolder;
}
//replace contents of view
#Override
public void onBindViewHolder(ViewHolder holder, int position){
holder.petInfo.setText(mAnimalData.get(position).getPetInfo());
PicassoClient.downloadImage(mContext,mAnimalData.get(position).getImgURL(), holder.imgURL);
}
//return size of dataset
public int getItemCount(){
return mAnimalData.size();
}
}
Fragment:
public class DogFragment extends Fragment {
public static final String ARG_PAGE = "ARG_PAGE";
private int mPage;
private RecyclerView mRecyclerView;
private RecyclerView.Adapter mCardAdapter;
private RecyclerView.LayoutManager mCardLayoutManager;
DatabaseReference mDatabaseReference;
FirebaseHelper helper;
public static DogFragment newInstance(int page) {
DogFragment dogFragment = new DogFragment();
Bundle args = new Bundle();
args.putInt(ARG_PAGE, page);
dogFragment.setArguments(args);
return dogFragment;
}
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
mPage = getArguments().getInt(ARG_PAGE);
}
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
// Inflate the layout for this fragment
View rootView = inflater.inflate(R.layout.fragment_dog, container, false);
//cardview
mRecyclerView = (RecyclerView)rootView.findViewById(R.id.card_view);
//setup firebase
mDatabaseReference = FirebaseDatabase.getInstance().getReference();
helper= new FirebaseHelper(mDatabaseReference);
//create adapter class
//mCardAdapter = new CardViewAdapter(mAimalTypeList);
mCardAdapter = new CardViewAdapter(getActivity().getApplicationContext(), helper.retrieve());
mRecyclerView.setAdapter(mCardAdapter);
//add linear layout manager
mCardLayoutManager = new LinearLayoutManager(getActivity());
mRecyclerView.setLayoutManager(mCardLayoutManager);
//preparePetData();
return rootView;
}
}
Picasso:
public class PicassoClient {
public static void downloadImage(Context context, String url, ImageView img){
if(url != null && url.length()>0){
Picasso.with(context).load(url).placeholder(R.drawable.placeholder).into(img);
}
else {
Picasso.with(context).load(R.drawable.placeholder).into(img);
}
}
}
Your call to helper.retrieve() is kicking off mDatabase.addChildEventListener the results of which will come back asynchronously....in the meantime you're returning empty list from that method (default value of animal). You need to update adapter when results come back (after you've called fetchData(dataSnapshot);)