Why is firebase recycler adapter returning null - android

I am really stuck here, I need to get the Post class value that is held in users/user_id/latest_post only some users have this value. so I thought:
query.addChildEventListener(new ChildEventListener() {
#Override
public void onChildAdded(DataSnapshot dataSnapshot, String prevChildKey) {
if (dataSnapshot.hasChild("latest_post")) {
Post latest = dataSnapshot.child("latest_post").getValue(Post.class);
latest_posts = latest;
post = latest;
}
}
should work, it does in getting me the values and ignoring the ones that don't contain a latest_posts child. But my recycler adapter and view-holder doesn't seem to use this and when I try setting up the recycler view is says the value it's trying to get is null.
FirebaseRecyclerOptions<Post> firebaseRecyclerOptions = new FirebaseRecyclerOptions.Builder<Post>()
.setQuery(query, Post.class)
.build();
firebaseRecyclerAdapter = new FirebaseRecyclerAdapter<Post, PostHolder>(firebaseRecyclerOptions) {
#Override
protected void onBindViewHolder(#NonNull PostHolder postHolder, int position, #NonNull Post post) {
postHolder.setPost(post);
}
#Override
public PostHolder onCreateViewHolder(ViewGroup parent, int viewType) {
View view = LayoutInflater.from(parent.getContext()).inflate(R.layout.post_content, parent, false);
return new PostHolder(view);
}
};
Here is the rest of the firebase adapter ^ and then here is the setPost function:
void setPost(Post post) {
String key = post.getPost_id();
Integer reads = post.getReads();
String titleString = post.getTitle();
String bodyString = post.getBody();
String usernameString = post.getAuthor();
String category = post.getCategory();
System.out.println("setPost " + usernameString);
...
}
Top of file I am holding:
Post post;
which is updated with the values in the childEventListener. Any ideas where I am messing up? Thank you.
UPDATE:
I have made these changes using my User class which contains the Post class (latest_post):
void setupRecycler(Query query) {
query = FirebaseDatabase.getInstance()
.getReference()
.child("users");
FirebaseRecyclerOptions<User> firebaseRecyclerOptions = new FirebaseRecyclerOptions.Builder<User>()
.setQuery(query, User.class)
.build();
firebaseRecyclerAdapter = new FirebaseRecyclerAdapter<User, PostHolder>(firebaseRecyclerOptions) {
#Override
protected void onBindViewHolder(#NonNull PostHolder postHolder, int position, #NonNull User user) {
if (user.getLatest_post().getAuthor() != null) {
postHolder.setPost(user);
}
}
#Override
public PostHolder onCreateViewHolder(ViewGroup parent, int viewType) {
View view = LayoutInflater.from(parent.getContext()).inflate(R.layout.post_content, parent, false);
return new PostHolder(view);
}
};
}
Now I am trying to filter when the setPost(user) is called so it only lets through if the latest_posts value is not null. But I must be misunderstanding something, because it gives me the first two names but still attempts to use the vaues which dont have latest_post which results in crashing due to null.
UPDATE 2:
Getting closer, this works:
query = FirebaseDatabase.getInstance()
.getReference()
.child("users").orderByChild("latest_post");
I'm guessing because it orders them by the users that have latest_post, but it crashes if I scroll to the bottom because Then all the rest are still there, so it attempts to set a string value to a textView when it is null. How do I exclude these pesky things?

It was because you can't filter a query to exclude posts that do not exist, and you do not have access to the list that firebaseRecyclerAdapter uses. The only solution to accurately and safely filter the data the way I needed was to use a custom recyclerView Adapter, and a list of my class, and filter and order the list as needed after the query.

Related

Android Firebase - how to get child node data

I have node of "genresComments" that saves comments of each user to for each video id. It goes like that Genre -> video ID -> user ID:Data.
What im trying to get is all the user's id and their data (The data i mean:comment,profilePicture,username).
thats the query that should point to that data
Query query = FirebaseDatabase.getInstance().getReference(Params.GENRESCOMMENTS).child(genre).child(videoID);
But i'm sure that it points only on the "users id" and not bringing me the inside data that i need.
My question is how do i get for each "video id" all his "user id" and his data (comment,profilePicture,username).
EDIT
#Override
public void onViewCreated(#NonNull View view, #Nullable Bundle savedInstanceState) {
super.onViewCreated(view, savedInstanceState);
videoID = getArguments().getString(Params.VIDEOID);
genre = getArguments().getString(Params.GENRE);
progressBar.setVisibility(View.VISIBLE);
if(videoID != null){
Query query = FirebaseDatabase.getInstance().getReference(Params.GENRESCOMMENTS).child(genre).child(videoID);
options = new FirebaseRecyclerOptions.Builder<Comment>().setQuery(query,Comment.class).build();
adapter = new FirebaseRecyclerAdapter<Comment,CommentsViewHolder>(options) {
#Override
protected void onBindViewHolder(CommentsViewHolder holder, int position, Comment model) {
holder.userName.setText(model.getUserName());
holder.comment.setText(model.getComment());
Glide.with(getContext()).load(model.getUserProfile()).into(holder.userProfile);
}
#Override
public CommentsViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
View view = LayoutInflater.from(parent.getContext()).inflate(R.layout.comment_item,parent,false);
return new CommentsViewHolder(view) ;
}
};
}
if(adapter != null) {
rvComments.setAdapter(adapter);
rvComments.setLayoutManager(new LinearLayoutManager(getContext()));
}
}
I use this query for recycler view
Do like below code (it may get errors): learn about event listener first
FirebaseDatabase.getInstance().getReference(Params.GENRESCOMMENTS).child(genre).child(videoID).addValueEventListener(new ValueEventListener(Datasnapshot snap){
for(DataSnapshot s:snap.getChildren()){
Comment c=s.getValue(Comment.class);
//c.getPRofilePic c.getComment();
}
});
class Comment {
private String comment;
private String profilePic;
private String username;
//getter setter
}

is it possible to combine FirestorRecyclerAdaper with pagination?

I am using FirestoreRecyclerAdaper with the normal form of retrieving and showing data.
my data becomes bigger and I want to make pagination in it, but I didn't find any tutorial to this point. I read documentations but nothing show how to do that because their is only one adapter and 2 queries and FirestorRecyclerAdaper accept only one query.
so is their a solution without changing my code?
final Query query = firebaseFirestore
.collection("Ads")
.orderBy("creationDate", Query.Direction.DESCENDING).limit(5);
query.get().addOnSuccessListener(new OnSuccessListener<QuerySnapshot>() {
#Override
public void onSuccess(QuerySnapshot queryDocumentSnapshots) {
DocumentSnapshot lastVisible = queryDocumentSnapshots
.getDocuments().get(queryDocumentSnapshots.size() - 1);
Query next = firebaseFirestore.collection("Ads")
.orderBy("creationDate")
.startAfter(lastVisible)
.limit(10);
}
});
options = new FirestoreRecyclerOptions
.Builder<MyAdCard>()
.setQuery(query, MyAdCard.class)
.build();
dapter = new FirestoreRecyclerAdapter<MyAdCard, AllCardViewHolder>(options) {
#Override
protected void onBindViewHolder(#NonNull final AllCardViewHolder holder, final int position, #NonNull MyAdCard model) {
holder.publicAd_discription.setText(model.getMyAddiscriptiontxt());
}
#NonNull
#Override
public AllCardViewHolder onCreateViewHolder(#NonNull ViewGroup parent, int viewType) {
View view = LayoutInflater.from(parent.getContext())
.inflate(R.layout.cardview_categoryads, parent, false);
return new AllCardViewHolder(view);
}
};
categoryAdsRV.setAdapter(dapter);
private class AllCardViewHolder extends RecyclerView.ViewHolder {
public AllCardViewHolder(View itemView) {
super(itemView);
}
TextView publicAd_discription = itemView.findViewById(R.id.publicAd_Discription);
}
#Override
protected void onStart() {
super.onStart();
dapter.startListening();
}
#Override
protected void onStop() {
super.onStop();
if ( dapter != null ) dapter.stopListening();
}
There is nothing you can do here without changing your code significantly.
There is a FirestorePagingAdapter from Firebase-UI that may help you with the changes you'll need to make.
There is also a sample code I wrote with one example of using Android Architecture Components Paging along with both Firestore and Realtime Database.

Cannot retrieve data in ascending order

I want to retrieve data in ascending order, but received data somehow added to recyclerview in descending order.
Firebase Database:
What I am doing:
DatabaseReference mDatabase = FirebaseDatabase.getInstance().getReference().child("/Teacher");
Query query = mDatabase.orderByChild("rating");
FirebaseRecyclerOptions<Teacher> options =
new FirebaseRecyclerOptions.Builder<Teacher>()
.setQuery(query, Teacher.class)
.build();
FirebaseRecyclerAdapter adapter = new FirebaseRecyclerAdapter<Teacher, TeacherViewHolder>(options) {
#NonNull
#Override
public TeacherViewHolder onCreateViewHolder(#NonNull ViewGroup parent, int viewType) {
View view = LayoutInflater.from(parent.getContext())
.inflate(R.layout.teacher_list_item, parent, false);
return new TeacherViewHolder(view);
}
#Override
protected void onBindViewHolder(#NonNull final TeacherViewHolder holder, int position, #NonNull final Teacher model) {
// some stuff here
}
};
Since you can't do that natively with the RTDB, you'll probably want to do something like this:
LinearLayoutManager layoutManager = new LinearLayoutManager(context);
layoutManager.setReverseLayout(true);
layoutManager.setStackFromEnd(true);
recyclerView.setLayoutManager(layoutManager);
See https://stackoverflow.com/a/27727398/4548500 for more details.
To get a sorted and filtered result, you have to pass a query into the FirebaseRecyclerAdapter constructor:
public MyFireAdapterDiasFiestaRecyclerView(
Class<DiaFiestaMeta> modelClass,
int modelLayout,
Class<MyFireViewHolder> viewHolderClass,
Query query) {
...
And then invoke it with a query that orders and filters:
adapter = new MyFireAdapterDiasFiestaRecyclerView(
DiaFiestaMeta.class,
layout_that_you_use,
MyFireViewHolder.class,
ref.orderByChild("property_to_sort_and_filter_on").equalTo("value_to_filter_on")
);

How do I search (SELECT and WHERE) in firebase and put them to recycle view

I'm trying to retrieve data from (Confesses table) on firebase database, but not all data, I want to make a condition on it and show the result in recycleView, it worked for me, I retrieve the specific data that I want but it call an empty row in the recycleView ...
I have 3 object in my firebase database, two object achieve the condition that I want, the other not achieve it ... so when I'll show the data, just the two object must be appear, unfortunately all the object appear, but the object that not achieving the condition appear but empty ... see the picture below
Initialisation :
rView = (RecyclerView) findViewById(R.id.confess_list);
rView.setHasFixedSize(true);
rView.setLayoutManager(new LinearLayoutManager(this));
mFirebaseDatabase = FirebaseDatabase.getInstance().getReference().child("Confesses");
setupAdapter();
rView.setAdapter(mPostAdapter);
here is where I put the condition
private void setupAdapter() {
mPostAdapter = new FirebaseRecyclerAdapter<Confess, PostViewHolder>(
Confess.class,
R.layout.sample_confess,
PostViewHolder.class,
mFirebaseDatabase
) {
#Override
protected void populateViewHolder(PostViewHolder viewHolder, final Confess model, int position) {
db = new SQLiteHandler(getApplicationContext());
final HashMap<String, String> user = db.getUserDetails();
if (model.getIdReceiver().equals(user.get("idUser"))){
viewHolder.setContent(StringEscapeUtils.unescapeJava(model.getConfessContent()));
viewHolder.setDate(model.getCreated_at());
}
}
};
}
ViewHolder class
public static class PostViewHolder extends RecyclerView.ViewHolder {
public EmojiconTextView emojyView;
public TextView dateView;
public PostViewHolder(View itemView) {
super(itemView);
emojyView = (EmojiconTextView) itemView.findViewById(R.id.emojicon_text_viewMain);
dateView = (TextView) itemView.findViewById(R.id.c_date);
}
public void setContent(String content) {
emojyView.setText(content);
}
public void setDate(String date) {
dateView.setText(date);
}
}
I fixed this problem by adding a filter to my 'FirebaseRecyclerAdapter'
Now it's working :D
mPostAdapter = new FirebaseRecyclerAdapter<Confess, PostViewHolder>(
Confess.class,
R.layout.sample_confess,
PostViewHolder.class,
mFirebaseDatabase.orderByChild("idReceiver").equalTo(userId)
)
to make query in Firebase will be Like
mFirebaseDatabase = FirebaseDatabase.getInstance()
.getReference().child("Confesses")
.orderByChild("YOUR_FIELD").equalTo("Value")
.getRef()
But You can`t query AND , OR .. which mean there will be only one orderByChild in your Query
and there are more Queries You can Use Like
.startAt(" ")
.endAt("")
.limitToFirst()
.limitToLast()

FirebaseRecyclerAdapter add a hasChild() method?

Here's my database:
Database:{
X:{
JK-KDUKSIDKSIIJDSL1:{
text:"hello",
name:"Donald J. Drunk"
}
JK-KDadDFDDIJDSL1:{
name:"Killery Hlinton"
}
}
}
And I want to filter my FirebaseRecyclerAdapter such that only add to my RecyclerView data that contains the key text. How is this possible? How can I add it? Current code:
mAdapter = new FirebaseRecyclerAdapter<Campaign, CampaignHolder>(Campaign.class, R.layout.recyclerview_template, CampaignHolder.class, ref) {
#Override
public void populateViewHolder(final CampaignHolder viewHolder, final Campaign campaign, final int position) {
findViewById(R.id.progress_bar).setVisibility(View.INVISIBLE);
MainActivity.this.holder = viewHolder;
viewHolder.setTitle(campaign.title);
//... Other "set" methods
}
}
You could try overriding the onBindViewHolder method in your FirebaseRecyclerAdapter. Something like this:
mAdapter = new FirebaseRecyclerAdapter<Campaign, CampaignHolder>(Campaign.class, R.layout.recyclerview_template, CampaignHolder.class, ref) {
#Override
public void onBindViewHolder(CampaignHolder viewHolder, int position) {
Campaign model = getItem(position);
if(model.getText() != null){
populateViewHolder(viewHolder, model, position);
}
}
#Override
public void populateViewHolder(final CampaignHolder viewHolder, final Campaign campaign, final int position) {
findViewById(R.id.progress_bar).setVisibility(View.INVISIBLE);
MainActivity.this.holder = viewHolder;
viewHolder.setTitle(campaign.title);
//... Other "set" methods
}
};
With this approach you would still pull all data at the query location but entries without a text attribute just wouldn't be displayed. If that is unsatisfactory and you want to minimize the amount of data you download per query then the only other option I see is closer to what is mentioned in the comments above - meaning you would need to create a separate location that only stores those entries which have a text value.

Categories

Resources