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")
);
Related
I cant find a way to set image to imageView from drawable folder depending on string data received from Firebase Database.
I get values from Firebase Database like this:
DatabaseReference personsRef = FirebaseDatabase.getInstance().getReference().child("Persons");
Query personsQuery = personsRef.orderByKey();
FirebaseRecyclerOptions personsOptions = new FirebaseRecyclerOptions.Builder<Adapter>().setQuery(personsQuery, Adapter.class).build();
mAdapter = new FirebaseRecyclerAdapter<Adapter, Tab1.MyViewHolder>(personsOptions) {
#Override
protected void onBindViewHolder(Tab1.MyViewHolder holder, final int position, final Adapter model) {
holder.setTitle(model.getTitle());
holder.setDate(model.getDate());
}
#Override
public Tab1.MyViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
View view = LayoutInflater.from(parent.getContext()).inflate(R.layout.recycle_tab1, parent, false);
return new Tab1.MyViewHolder(view);
}
};
The goal is to populate imageViews in RecyclerView with images from drawable folder depending on data loaded from Firebase. Something like: if "title" loaded from firebase = 1, set imageView to R.drawable.thisPerson1.
You can append your received string to ImageView Resource ID
DatabaseReference personsRef = FirebaseDatabase.getInstance().getReference().child("Persons");
Query personsQuery = personsRef.orderByKey();
FirebaseRecyclerOptions personsOptions = new FirebaseRecyclerOptions.Builder<Adapter>().setQuery(personsQuery, Adapter.class).build();
mAdapter = new FirebaseRecyclerAdapter<Adapter, Tab1.MyViewHolder>(personsOptions) {
#Override
protected void onBindViewHolder(Tab1.MyViewHolder holder, final int position, final Adapter model) {
holder.setTitle(model.getTitle());
holder.setDate(model.getDate());
holder.yourImageView.setImageResource(R.drawable+"."+model.getImage())
}
#Override
public Tab1.MyViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
View view = LayoutInflater.from(parent.getContext()).inflate(R.layout.recycle_tab1, parent, false);
return new Tab1.MyViewHolder(view);
}
};
If title is number like 0..10 then u could try to create res array:
if 1..10 then try to use model.getTitle() - 1 etc.
<integer-array name="some_name">
<item>#drawable/thisPerson1</item>
<item>#drawable/thisPerson2</item>
<item>#drawable/thisPerson3</item>
<item>#drawable/thisPerson4</item>
</integer-array>
private TypedArray imagesArray = getResources().obtainTypedArray(R.array.some_name);
private int image = imagesArray.getResourceId(imagesArray.getIndex(title), defaultValue)
ImageView.setBackgroundResource(image)
imagesArray.recycle()
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.
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.
How can i retrieve the keys for my database entries and map them to my java objects, so that i can update the content of each individual object in the database? I want to retrieve the "TODO KEY" as represented in the JSON below.
Database
{
"todos" : {
"7Y3s5KPhyLU8mR7cbUGNbcnNQ7f1 (USER KEY)" : {
"-LCddfFC048CowqkTfV1 (TODO KEY)" : {
"description" : "vhh",
"title" : "hh"
},
"-LCdiAkltHn3Zs47Fdyg" : {
"description" : "hg5hh",
"title" : "bcgyi"
}
}
}
}
Android code
mUserId = FirebaseAuth.getInstance().getCurrentUser().getUid();
mQuery = FirebaseDatabase.getInstance().getReference().child("todos/" + mUserId);
//Initialize RecyclerView
mRecyclerView = findViewById(R.id.recyclerView);
//Set layout manager for RecyclerView
mRecyclerView.setLayoutManager(new LinearLayoutManager(this));
//Initialize options for adapter
FirebaseRecyclerOptions<Todo> options =
new FirebaseRecyclerOptions.Builder<Todo>()
.setQuery(mQuery, Todo.class)
.build();
//Initialize adapter
mAdapter = new FirebaseRecyclerAdapter<Todo, TodoHolder>(options) {
#Override
public TodoHolder onCreateViewHolder(ViewGroup parent, int viewType) {
// Create a new instance of the ViewHolder, in this case we are using a custom
// layout called R.layout.message for each item
View view = LayoutInflater.from(parent.getContext())
.inflate(R.layout.list_item, parent, false);
return new TodoHolder(view);
}
#Override
protected void onBindViewHolder(TodoHolder holder, int position, Todo todo) {
// Bind the Chat object to the ChatHolder
holder.bind(todo);
}
};
//Connect adapter to recyclerview
mRecyclerView.setAdapter(mAdapter);
To get the key in your onBindViewHolder, you look it up from the adapter based on the position:
DatabaseReference ref = mAdapter.getReference(position);
String key = ref.getKey();
I have an app I am working on that needs live queries using location from the user. Writing to the geofire node is okay but I have trouble on reading. Once I get the id's how do I make a query with them and display data using the firebase recycleradapter?
Here is my code so far (without Geofire):
FirebaseRecyclerOptions<Venue> options =
new FirebaseRecyclerOptions.Builder<Venue>()
.setQuery(filterRef, Venue.class)
.build();
adapter = new FirebaseRecyclerAdapter<Venue, VenueViewHolder>(options) {
#Override
public VenueViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
View view = LayoutInflater.from(parent.getContext())
.inflate(R.layout.single_venue_item, parent, false);
return new VenueViewHolder(view);
}
#Override
protected void onBindViewHolder(final VenueViewHolder holder, final int position, Venue model) {
final String venueName = model.getVenueName();
holder.venueName.setText(venueName);
Glide.with(holder.mView.getContext())
.load(model.getVenueMainImage())
.apply(new RequestOptions()
.placeholder(R.mipmap.ic_launcher_round))
.into(holder.venueMainImage);
}
};
venuesRecyclerView.setLayoutManager(mLinearLayoutManager);
venuesRecyclerView.setAdapter(adapter);