Android Firebase Nested Query - android

I'm using FirebaseListAdapter and trying to get a list of open chat rooms from my Firebase Database, the structure is pretty simple:
This is what I get when I query:
{-KY99IS2mLzayD4HDyd6={location={...}, posts={....} , title="chatname"}
And what I'm trying to achieve is to get the data without the ID part, so it would fit my object builder, something like that:
{location={...}, posts={....} , title="chatname"}
I know that ChildEventListener does that, but I don't have an option to use it with the FirebaseListAdapter, so I hope there's another way to do that.
My code is:
FirebaseListAdapter<ChatRoom> firebaseListAdapter = new FirebaseListAdapter<ChatRoom>(this,ChatRoom.class,R.layout.chatslist_row,myRef3) {
#Override
protected void populateView(View v, ChatRoom chatRoom, int position) {
System.out.println(chatRoom.title);
}
};
But it doesn't work because of the key part, it can't use my ChatRoom class object builder.
Thanks!

You can first get the id (KY99IS2mLzayD4HDyd6) from the child event listener.
Then made a new database reference with the id (KY99IS2mLzayD4HDyd6) and call for child event listener again.
mDatabase = databaseRef.getReference("chats/KY99IS2mLzayD4HDyd6");
if you call mDatabase now you will get {location={...}, posts={....} , title="chatname"}.
I have solved my issue like that. But not for FirebaseListAdapter. Make your own listview and adapter this might be more flexible.

Related

How to access database from RecyclerView Adapter holder?

I'm in need of advice on how to get data from the database, or whatever approach is best, from a RecyclerView adapter onBindViewHolder() method. Basically I have a list of Transactions that the ViewHolder cycles through, which contains an ID for a related entity called Payee, which I can obtain by accessing the Transaction's getPayeeByID method. (That method already exists to pull the info in the repository and Dao and works fine.) The problem is, how do I access that method from this screen? I need to know how get to it from here so I can create a new Payee based on the pulled PayeeId, in order to set the holder.payee.setText field with the name of the associated Payee. I have no idea how to do that from here.
#Override
public void onBindViewHolder(#NonNull ViewHolder holder, int position) {
final Transaction transaction = tTransactions.get(holder.getAdapterPosition());
holder.payee.setText( ????????? ) ;
holder.date.setText(date);
holder.transAmount.setText(amount);
I am happy to add more code if needed.
I realized the solution to this. I just created an instance of the repository and accessed the DB through that. See below:
AppRepository repository = new AppRepository(tContext);
final Payee payee = repository.getPayeeById(transaction.getPayeeId());
holder.payee.setText(payee.getName());

Offline sort of FirebaseRecyclerAdapter

I'm currently using FirebaseRecyclerAdapter to retrieve data from a Firebase database, and I've pretty much worked out how to retrieve the data in the order I desire.
To avoid duplication and ease database maintenance, I'd like to add a key to a database entry that allows me to return queries based on that key. I was originally storing data twice. Once for all to see, and once if a user had joined a certain group (under groupName).
To return a query based on group, my original search was as follows:
databaseReference.child(groupName).child("exerciseId"+mExerciseId).orderByChild(sortOrder).limitToFirst(100);
but I believe duplication can be avoided by adding the key "group" to my post. (it also make maintenance much easier as users switch groups).
The "group" database query has now become:
databaseReference.child("exerciseId"+mExerciseId).orderByChild("group").equalTo(groupName);
All is good, except that the data is no longer sorted as per "sortOrder". As firebase does not allow multiple sort criteria, I believe my solution lies in offline sorting.
So, how does one sort the adapter offline?
My adapter is pretty standard:
mAdapter = new FirebaseRecyclerAdapter<Post, PostViewHolder>(Post.class, R.layout.item_post, PostViewHolder.class, dataQuery)
{
#Override
protected void populateViewHolder(final PostViewHolder viewHolder, final Post model, final int position)
{
final DatabaseReference postRef = getRef(position);
// Bind Post to ViewHolder, setting OnClickListener for the star button
viewHolder.bindToPost(model, position, postRef.getKey(), null);
}
mRecycler.setAdapter(mAdapter);
}
I've implemented Comparable in Post, the problem is where is the data stored so that I can pass it to Collections.sort() in this sort of way:
private List<Post> mPosts = new ArrayList<>();
mPosts.add(model);
Collections.sort(mPosts, Post.Comparators.ALLTIME);
The adapters in the FirebaseUI library currently always display data in the order that it is returned by the underlying FirebaseDatabase reference or Query.
You could file a feature request on the Github repo for it (since I'm not sure it is covered in this one yet). Alternatively you could fork the library and roll your own implementation of this functionality.
To feedback on the solution I came up with. I ended up populating my own List, which I can then sort or add to (if using multiple queries) depending on what I'm trying to achieve. This is then displayed using a standard RecyclerView adapter. It works great.
private final List<Post> postList = new ArrayList<>();
dataQuery.addListenerForSingleValueEvent(new ValueEventListener()
{
#Override
public void onDataChange(DataSnapshot dataSnapshot)
{
postList.clear(); // in this example it's a newQuery, so clear postList
for (DataSnapshot child : dataSnapshot.getChildren())
{
Post post = child.getValue(Post.class);
postList.add(post);
int myPosition = sortData(); // uses Collections.sort() to sort data
mAdapter.addPosts(postList);
mAdapter.notifyDataSetChanged();
mRecycler.scrollToPosition(myPosition);
}
}
});

Filter results in FirebaseRecyclerAdapter

I am new to Android and just started to understand some concepts like the RecyclerView. I am using Firebase as a database so I implemented the Firebase solution for that.
My Adapter:
FirebaseRecyclerAdapter<Offer,OfferViewHolder> adapter = new FirebaseRecyclerAdapter<Offer, OfferViewHolder>(
Offer.class,
R.layout.card_item,
OfferViewHolder.class,
mDatabaseReference.child("offer").getRef()
) {
#Override
protected void populateViewHolder(OfferViewHolder viewHolder, Offer model, int position) {
if(tvNoMovies.getVisibility()== View.VISIBLE){
tvNoMovies.setVisibility(View.GONE);
}
viewHolder.tvHeading.setText(model.getHeader());
viewHolder.tvStoreName.setText(model.getStoreName());
}
};
Now I have two questions:
Is it possible to filter results inside the adapter or do i have to use ChildEventListeners for that?
When referencing to a key that contains an Array or an object itself how to retrieve child values?
You can initialize the FirebaseRecyclerAdapter with either a DatabaseReference or a Query. As its name implies, the latter allows you to get a subset of the children at a specific location in the database.
For example say if you want to only show offers from a specific store:
DatabaseReference offers = mDatabaseReference.child("offer").getRef();
Query storeOffers = offers.orderByChild("storeName").equalTo("A. lazzi's store");
FirebaseRecyclerAdapter<Offer,OfferViewHolder> adapter = new FirebaseRecyclerAdapter<Offer, OfferViewHolder>(
Offer.class,
R.layout.card_item,
OfferViewHolder.class,
storeOffers
) {

How do I utilize filters and child elements in Google Firebase Database

Working on an Android app that is using the new Firebase Database framework. It has data objects that are modeled like this:
Where the Top parent (1234-4321) is the 'chat room', the data object are the 'chat messages', and the numbered items (0, 1, 2) are the 'individual message'.
I am able to get the entire Database without any trouble and read it via listeners:
FirebaseDatabase database = FirebaseDatabase.getInstance();
DatabaseReference myRef = database.getReference();
myRef.addChildEventListener(this);
myRef.addValueEventListener(this);
And I am able to get a single child in this fashion:
FirebaseDatabase database = FirebaseDatabase.getInstance();
String id = "1234-4321";
DatabaseReference myRef = database.getReference().child(id);
myRef.addChildEventListener(this);
myRef.addValueEventListener(this);
But I cannot for the life of me figure out how to get multiple objects of the same type. What I mean is, a user will be able to get More than one chat room (IE, both '1234-4321' and '1234-4432'), but the only way I can see to do this is either to:
1) loop through the onChildAdded or onDataChange listeners, separate out the items by matching the String ids, and updating them. This is, however, extremely inefficient as I am parsing the entire Database, which could be quite large
#Override
public void onChildAdded(DataSnapshot dataSnapshot, String s) {
if(dataSnapshot != null){
try {
ChatObjectV2 objectV2 = (ChatObjectV2) dataSnapshot.getValue();
//Check here for ids and loop through everything
} catch (Exception e){
e.printStackTrace();
}
}
}
or
2) To add a specific child, but if I try to add more children it is going 'deeper' into the nested object when I want it to go 'wider'.
//This won't work because it is going 'deeper' instead of 'wider'
String id = "1234-4321";
String id2 = "1234-4432";
Query myQuery = myRef.child(id).child(id2);
And then loop through in the listener the same way, but, I would need to create a different DatabaseReference for every chat room, which is horribly inefficient.
It looks like the solution is probably to use filters, but I cannot for the life of me figure out how to utilize them in the existing FirebaseDatabase and DatabaseReference objects. Does anyone have any idea how to make a filter work with regards to the data schema / model I have listed here?
Thanks for the help!
I would try to explain you the basic use of filtering in these examples:
//getting first two chat rooms
Query chatRoomsQuery = databaseReference.limitToLast(2);
//getting last two chat rooms
Query chatRoomsQuery = databaseReference.limitToFirst(2)
//getting all active id
Query chatRoomsQuery = databaseReference.orderByChild("active").equalTo(true);
This is just a basic sample I would encourage you to go through this blog. Which explains advanced queries amazingly.
Alternatively, you can also go through these docs. They are different than what you shared.
Do let me know if this is what you were looking for.

Android and parse

i made a listview with all the posts in the list.
what i want is when i click the child in the list i want another activity to be opened showing that specific post and the related comments
the question is how to know which item is clicked and how to show that particular post ParseObject in next activity
as they do in messaging app in which you click the message from the listview and subsequent messages are shown in the next activity
i might be very thankful to you if you solve this for me!!
Please Try this code:
Please implement your object class with Serializable
listView.setOnItemClickListener(new OnItemClickListener() {
#Override
public void onItemClick(AdapterView<?> adapter, View v, int position,
long arg3) {
try
{
Log.v("position",position); // hear is your list item position
MyClass obj = new MyClass(); // Class must be implements with Serializable
Intent showintent = new Intent(context,<activity class to open>);
showcontactintent.putExtra("obj",obj);
startActivity(showintent);
}
catch(Exception e)
{
e.printStackTrace();
}
}
});
Use: Relational Data
Objects can have relationships with other objects. To model this behavior, any ParseObject can be used as a value in other ParseObjects. Internally, the Parse framework will store the referred-to object in just one place, to maintain consistency.
For example, each Comment in a blogging app might correspond to one Post. To create a new Post with a single Comment, you could write:
// Create the post
ParseObject myPost = new ParseObject("Post");
myPost.put("title", "I'm Hungry");
myPost.put("content", "Where should we go for lunch?");
// Create the comment
ParseObject myComment = new ParseObject("Comment");
myComment.put("content", "Let's do Sushirrito.");
// Add a relation between the Post and Comment
myComment.put("parent", myPost);
// This will save both myPost and myComment
myComment.saveInBackground();
You can also link objects using just their objectIds like so:
// Add a relation between the Post with objectId "1zEcyElZ80" and the comment
myComment.put("parent", ParseObject.createWithoutData("Post", "1zEcyElZ80"));
By default, when fetching an object, related ParseObjects are not fetched. These objects' values cannot be retrieved until they have been fetched like so:
fetchedComment.getParseObject("post")
.fetchIfNeededInBackground(new GetCallback<ParseObject>() {
public void done(ParseObject post, ParseException e) {
String title = post.getString("title");
// Do something with your new title variable
}
});
You can also model a many-to-many relation using the ParseRelation object. This works similar to List, except that you don't need to download all the ParseObjects in a relation at once. This allows ParseRelation to scale to many more objects than the List approach. For example, a User may have many Posts that they might like. In this case, you can store the set of Posts that a User likes using getRelation. In order to add a post to the list, the code would look something like:
ParseUser user = ParseUser.getCurrentUser();
ParseRelation<ParseObject> relation = user.getRelation("likes");
relation.add(post);
user.saveInBackground();
You can remove a post from the ParseRelation with something like:
relation.remove(post);
For more read: https://parse.com/docs/android/guide#objects-relational-data
^why did I copy all the words here instead of just providing the link? Because parse links are broken sometimes and doesn't direct you to the section you need (instead it just sends you to https://parse.com/docs/android/guide and because the doc is so large, you won't be able to find it.

Categories

Resources