I have a chat app as part of my Android app that stores all messages in a chat room under a Firebase database reference that carries the ID number for that room. As it stands, the RecyclerView that holds the messages in the chat Activity downloads all messages in that room whenever the user enters it, consuming a potentially unwieldy amount of data. How should I go about making it only download the X most recent messages and download X more if the user scrolls to top?
Here is my adapter:
public class ChatRecyclerViewAdapter extends RecyclerView.Adapter<ChatRecyclerViewAdapter.ViewHolder> {
private static final String TAG = "ChatRecyclerViewAdapter";
private String mRoomID;
private Context mContext;
private DatabaseReference mDatabaseReference;
private ArrayList<Message> messageList;
private ChildEventListener mListener = new ChildEventListener() {
#Override
public void onChildAdded(#NonNull DataSnapshot dataSnapshot, #Nullable String s) {
// Convert data snapshot from Database into a Message Object
Message message = dataSnapshot.getValue(Message.class);
// Add it to an arrayList of Messages
messageList.add(message);
// Notice Changes
notifyItemInserted(messageList.size());
}
#Override
public void onChildChanged(#NonNull DataSnapshot dataSnapshot, #Nullable String s) {
}
#Override
public void onChildRemoved(#NonNull DataSnapshot dataSnapshot) {
}
#Override
public void onChildMoved(#NonNull DataSnapshot dataSnapshot, #Nullable String s) {
}
#Override
public void onCancelled(#NonNull DatabaseError databaseError) {
}
};
public ChatRecyclerViewAdapter(Context mContext, ArrayList<String> mMessage, ArrayList<String> mAuthor, String mRoomID, DatabaseReference reference) {
this.mContext = mContext;
this.mRoomID = mRoomID;
messageList = new ArrayList<>();
mDatabaseReference = reference.child(mRoomID+"_messages");
mDatabaseReference.addChildEventListener(mListener);
}
#NonNull
#Override
public ViewHolder onCreateViewHolder(#NonNull ViewGroup parent, int viewType) {
//This method loads layout(fields) of ViewHolder
View view = LayoutInflater.from(parent.getContext()).inflate(R.layout.chat_msg_row,parent, false);
ViewHolder holder = new ViewHolder(view);
return holder;
}
#Override
public void onBindViewHolder(#NonNull ViewHolder holder, int position) {
// This method fills fields with data for each list item
Log.d(TAG,"onBindViewHolder called");
Message message = messageList.get(position);
holder.message.setText(message.getMessage());
holder.author.setText(message.getAuthor()+":");
}
#Override
public int getItemCount() {
return messageList.size();
}
//Viewholder stores the information about the layout and content of each list item, and serves as a template for each item of a RecyclerView
public class ViewHolder extends RecyclerView.ViewHolder {
TextView author;
TextView message;
RelativeLayout singleMessageContainer;
public ViewHolder(View itemView) {
super(itemView);
author = itemView.findViewById(R.id.chatAuthor);
message = itemView.findViewById(R.id.chatMessage);
singleMessageContainer = itemView.findViewById(R.id.singleMessageContainer);
}
}
void cleanup() {
mDatabaseReference.removeEventListener(mListener);
}
}
If the messages are stored chronologically already (e.g. if you use push() to add them), you can order the messages by their key and get the most recent ones with:
mDatabaseReference = reference.child(mRoomID+"_messages");
Query recentMessages = mDatabaseReference.orderByKey().limitToLast(10);
recentMessages.addChildEventListener(mListener);
As Doug commented, please check the Firebase documentation on queries for more options
Related
I have two adapter:
One vertical and other horizontal
I would like to put data of an user in the list, so when I swipe horizontal I get just data of this user.
...
When I swipe vertical I would like to get another user
Like this:
Vertical swipe
User1 horizontal swipe -> {datauser1, datauser1}
Vertical swipe
User2 horizontal swipe -> {datauser2, datauser2}
...
I have a list with all users Id that I would like to retrieve data from when swipe left (horizontal)
But the problem is that when I swipe vertical I get always the same list with data from all users Id that I have in the list.
That's mean I get:
Vertical swipe
User1 horizontal swipe -> {datauser1, datauser1, datauser2, datauser2}
Vertical swipe
User1 horizontal swipe -> {datauser1, datauser1, datauser2, datauser2}
My approch to the problem was to get first the id's of the users and then iterate through the array with id's to get data from each userid in the array.
Vertical swipe load list of userid
Horizontal load JUST data from this user id
But it still doesn't work as I want to.
public class discover_fullscreen_adapter2 extends RecyclerView.Adapter {
private final int stories = 0;
private List<String> userList;
private Context mContext;
private List<Object> objectItems = new ArrayList<>();
private DatabaseReference databaseReference;
public discover_fullscreen_adapter2(Context context, List<String> userIdList) {
this.mContext = context;
userList = userIdList;
}
#NonNull
#Override
public RecyclerView.ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
int layout = 0;
RecyclerView.ViewHolder viewHolder;
// Identify viewType returned by getItemViewType(...)
// and return ViewHolder Accordingly
if (viewType == stories) {
layout = R.layout.view_pager_horizontal;
View contentView = LayoutInflater
.from(parent.getContext())
.inflate(layout, parent, false);
viewHolder = new testViewHolder2(contentView);
} else {
viewHolder = null;
}
return viewHolder;
}
#Override
public void onBindViewHolder(RecyclerView.ViewHolder holder, int position) {
int viewType = holder.getItemViewType();
if (viewType == stories) {
((testViewHolder2) holder).setViewPager2(((testViewHolder2) holder).videosViewPager, userList);
}
}
#Override
public int getItemCount() {
return userList.size();
}
public class testViewHolder2 extends RecyclerView.ViewHolder {
ViewPager2 videosViewPager;
int limit = 7, itemPos = 0;
private int currentPage = 0, intttt;
private int itemCurrentPositionOnViewPager;
private boolean loading = true;
public testViewHolder2(#NonNull View itemView) {
super(itemView);
videosViewPager = itemView.findViewById(R.id.viewPagerVideosHorizontal);
}
void setViewPager2(ViewPager2 videosViewPager, List<String> listUserId){
databaseReference = FirebaseDatabase.getInstance().getReference("stories");
Query queryFeed = databaseReference;
queryFeed.addChildEventListener(new ChildEventListener() {
#Override
public void onChildAdded(DataSnapshot dataSnapshot, String s) {
story_modell story = dataSnapshot.getValue(story_modell.class);
for (String id: listUserId){
if (id.equals(story.getUID())){
objectItems.add(story);
}
}
videosViewPager.setAdapter(new view_page_horizontal_adapter(mContext, objectItems));
}
#Override
public void onChildChanged(#NonNull DataSnapshot dataSnapshot, #Nullable String s) {
}
#Override
public void onChildRemoved(#NonNull DataSnapshot dataSnapshot) {
}
#Override
public void onChildMoved(#NonNull DataSnapshot dataSnapshot, #Nullable String s) {
}
#Override
public void onCancelled(#NonNull DatabaseError databaseError) {
}
});
}
}
}
I am attempting to load an undetermined number of viewHolders into a recyclerView with data retrieved from the Firebase Realtime Database. This is for a messaging component of my Android app. I am first iterating through a list of chat keys (see "Chat Keys" node below) stored in the database under the current user's userID. For each key, I access the specific associated chat (see "Chat Basics" node below). For testing purposes, I am only retrieving and setting one value type ("lastMessage"), however I intend to set multiple values per viewHolder after successful testing. I am unsure about how to correctly pass the data stored in my model class for each iteration to my onBindViewHolder in my adapter class for display in individual viewholders.
I have had success in retrieving "lastMessage" for each iteration in my fragment class, then passing a string to my adapter class for each iteration. The viewHolders did display the correct string values. Though I can do this successfully, I need to be able to pass an arrayList of data for each iteration, so that I am not limited to only passing a single value per key. Because the onBindViewHolder in the adapter class is position dependent, it is my understanding that I cannot simply pass an array list with simple strings, but should instead pass an instance (O.O.C -might not be the right word) of the model class in an arrayList to be further accessed in the adapter class.
One way or another, please help me load a set of values into an undetermined number of viewHolders for each Firebase Database chat key iteration based on the code provided below. Cheers.
Model Class:
public class MessagesList {
private String lastMessage;
//Default constructor
public MessagesList() {
}
public MessagesList(String lastMessage) {//String userName,, String profileImage) {
//this.userName = userName;
this.lastMessage = lastMessage;
//this.profileImage = profileImage;
}
public String getLastMessage() {
return lastMessage;
}
public void setLastMessage(String lastMessage) {
this.lastMessage = lastMessage;
}
}
Adapter Class:
public class TestRecyclerViewAdapter extends RecyclerView.Adapter<TestRecyclerViewAdapter.ViewHolder> {
private ItemClickListener mClickListener;
private LayoutInflater mInflater;
private ArrayList<MessagesList> mList;
//Data is passed into the constructor
public TestRecyclerViewAdapter(Context context, ArrayList<MessagesList> messagesList) {
this.mInflater = LayoutInflater.from(context);
this.mList = messagesList;
}
//Inflates the row layout from xml when needed
#Override
public ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
View view = mInflater.inflate(R.layout.standard_chat_list_layout, parent, false);
return new ViewHolder(view);
}
//Binds the data to the TextView in each row
#Override
public void onBindViewHolder(#NonNull ViewHolder holder, int position) {
holder.chatListLastMessage.setText(mList.get(position).getLastMessage());
}
//Total number of rows
#Override
public int getItemCount() {
return 0;
}
// stores and recycles views as they are scrolled off screen
public class ViewHolder extends RecyclerView.ViewHolder implements View.OnClickListener {
TextView chatListLastMessage;
ViewHolder(View itemView) {
super(itemView);
chatListLastMessage = itemView.findViewById(R.id.chatListLastMessage);
}
#Override
public void onClick(View view) {
if (mClickListener != null) mClickListener.onItemClick(view, getAdapterPosition());
}
}
// allows clicks events to be caught
void setClickListener(ItemClickListener itemClickListener) {
this.mClickListener = itemClickListener;
}
// parent activity will implement this method to respond to click events
public interface ItemClickListener {
void onItemClick(View view, int position);
}
}
Relevant Fragment:
public class MessagingFragment1 extends Fragment {
private DatabaseReference databaseReference;//, personalChatReference;
private RecyclerView directMessageRecycler;
private String currentUserID;
private TestRecyclerViewAdapter adapter;
private ArrayList<MessagesList> list_of_groups = new ArrayList<>();
public MessagingFragment1() {
// Required empty public constructor
}
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
final View rootView = inflater.inflate(R.layout.fragment_messaging1, container, false);
currentUserID = FirebaseAuth.getInstance().getCurrentUser().getUid();
databaseReference = FirebaseDatabase.getInstance().getReference();
directMessageRecycler = rootView.findViewById(R.id.directMessageRecycler);
//directMessageRecycler.setLayoutManager(new LinearLayoutManager(getActivity(), LinearLayoutManager.VERTICAL, false));
LinearLayoutManager linearLayoutManager = new LinearLayoutManager(getActivity());
directMessageRecycler.setLayoutManager(linearLayoutManager);
//get a reference to the join table mentioned above
databaseReference.child("Chat Keys").child(currentUserID).addValueEventListener(new ValueEventListener() {
#Override
public void onDataChange(#NonNull DataSnapshot dataSnapshot) {
for (DataSnapshot snapshot : dataSnapshot.getChildren()) {
String groupId = (snapshot.getKey());
databaseReference.child("Chat Basics").child(groupId).addListenerForSingleValueEvent(new ValueEventListener() {
#Override
public void onDataChange(#NonNull DataSnapshot dataSnapshotInner) {
MessagesList messagesList = dataSnapshotInner.getValue(MessagesList.class);
list_of_groups.add(messagesList);
adapter = new TestRecyclerViewAdapter(getActivity(), list_of_groups);
directMessageRecycler.setAdapter(adapter);
//adapter.setClickListener();
}
#Override
public void onCancelled(#NonNull DatabaseError databaseError) {
}
});
}
}
#Override
public void onCancelled(DatabaseError databaseError) {
}
});
return rootView;
}
Database Structure (x2):
Turns out I just forgot to return the correct item count
//Total number of rows
#Override
public int getItemCount() {
return mList.size();
}
and the result was a blank recyclerView. Despite the stupid reason for having posted this question, I will leave it as an example for others (like me) who've had difficulty finding a concise, full example of how to retrieve data from Firebase Database using simple key identifiers in one node to find the core data in another node.
For my first non-trivial Android app, I am making an app that involves chat rooms. I am using the chat room activity to teach myself recyclerView, which isn't covered as extensively as the somewhat antiquated listView in reference materials. I think I'm close to having a working recyclerView and adapter that I built trying to translate some of the elements of a listView into a recyclerView, but I am having trouble actually making the messages appear in the recyclerView. What am I doing wrong?
Here is my chat room activity:
public class ChatRoomActivity extends AppCompatActivity {
private static final String TAG = "Chat Room Activity";
private String mRoomID;
private String mRoomName;
private String mDisplayName;
private ArrayList<String> mUsernames = new ArrayList<>();
private ArrayList<String> mMessages = new ArrayList<>();
private RecyclerView mRecyclerView;
private EditText mInputText;
private ImageButton mSendButton;
private DatabaseReference mDatabaseReference;
private ChatRecyclerViewAdapter mAdapter;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_chat_room);
Log.d(TAG," onCreate: started.");
// identifies views
mInputText = findViewById(R.id.messageInput);
mSendButton = findViewById(R.id.sendButton);
//gets user display name from current user and gets Firebase reference
setupDisplayName();
mDatabaseReference = FirebaseDatabase.getInstance().getReference();
// gets Google Place ID from shared preferences
SharedPreferences preferences = getSharedPreferences(PLACE_PREFS, 0);
mRoomID = preferences.getString(PLACE_ID_KEY, null);
mRoomName = preferences.getString(PLACE_NAME_KEY, null);
Toast.makeText(this, mRoomID + mRoomName, Toast.LENGTH_LONG).show();
// Creates listener to send the message when the "enter" button is pressed
mInputText.setOnEditorActionListener(new TextView.OnEditorActionListener() {
#Override
public boolean onEditorAction(TextView v, int actionId, KeyEvent event) {
sendMessage();
return true;
}
});
// Adds an OnClickListener to the sendButton to send a message
mSendButton.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
sendMessage();
}
});
}
private void setupDisplayName() {
FirebaseUser user = FirebaseAuth.getInstance().getCurrentUser();
mDisplayName = user.getDisplayName();
}
private void sendMessage() {
// Grabs the text the user typed in and pushes the message to Firebase
String input = mInputText.getText().toString();
if (!input.equals("")) {
Log.d(TAG, "Message sent");
Message chat = new Message(input, mDisplayName);
mDatabaseReference.child(mRoomID + "_messages").push().setValue(chat);
mInputText.setText("");
}
}
private void initRecyclerView(){
Log.d(TAG, "initRecyclerView: init recyclerview" );
mRecyclerView = findViewById(R.id.chatRecyclerView);
mAdapter = new ChatRecyclerViewAdapter(this,mMessages,mUsernames,mRoomID,mDatabaseReference);
mRecyclerView.setAdapter(mAdapter);
mRecyclerView.setLayoutManager(new LinearLayoutManager(this));
}
#Override
protected void onStart() {
super.onStart();
initRecyclerView();
}
#Override
protected void onStop() {
super.onStop();
mAdapter.cleanup();
}
}
And here is my adapter:
public class ChatRecyclerViewAdapter extends RecyclerView.Adapter<ChatRecyclerViewAdapter.ViewHolder> {
private static final String TAG = "ChatRecyclerViewAdapter";
private ArrayList<String> mMessage = new ArrayList<>();
private ArrayList<String> mAuthor = new ArrayList<>();
private String mRoomID;
private Context mContext;
private DatabaseReference mDatabaseReference;
private ArrayList<DataSnapshot> mSnapshotList;
private ChildEventListener mListener = new ChildEventListener() {
#Override
public void onChildAdded(#NonNull DataSnapshot dataSnapshot, #Nullable String s) {
mSnapshotList.add(dataSnapshot);
notifyDataSetChanged();
}
#Override
public void onChildChanged(#NonNull DataSnapshot dataSnapshot, #Nullable String s) {
}
#Override
public void onChildRemoved(#NonNull DataSnapshot dataSnapshot) {
}
#Override
public void onChildMoved(#NonNull DataSnapshot dataSnapshot, #Nullable String s) {
}
#Override
public void onCancelled(#NonNull DatabaseError databaseError) {
}
};
public ChatRecyclerViewAdapter(Context mContext, ArrayList<String> mMessage, ArrayList<String> mAuthor, String mRoomID, DatabaseReference reference) {
this.mMessage = mMessage;
this.mAuthor = mAuthor;
this.mContext = mContext;
this.mRoomID = mRoomID;
mSnapshotList = new ArrayList<>();
mDatabaseReference = reference.child(mRoomID+"_messages");
mDatabaseReference.addChildEventListener(mListener);
}
#NonNull
#Override
public ViewHolder onCreateViewHolder(#NonNull ViewGroup parent, int viewType) {
View view = LayoutInflater.from(parent.getContext()).inflate(R.layout.chat_msg_row,parent, false);
ViewHolder holder = new ViewHolder(view);
return holder;
}
#Override
public void onBindViewHolder(#NonNull ViewHolder holder, int position) {
Log.d(TAG,"onBindViewHolder called");
holder.message.setText(mMessage.get(position));
holder.author.setText(mAuthor.get(position));
}
#Override
public int getItemCount() {
return mMessage.size();
}
public class ViewHolder extends RecyclerView.ViewHolder {
TextView author;
TextView message;
RelativeLayout singleMessageContainer;
public ViewHolder(View itemView) {
super(itemView);
author = itemView.findViewById(R.id.chatAuthor);
message = itemView.findViewById(R.id.chatMessage);
singleMessageContainer = itemView.findViewById(R.id.singleMessageContainer);
}
}
void cleanup() {
mDatabaseReference.removeEventListener(mListener);
}
}
The way you're inserting the records into ArrayList in onChildAdded() and retrieving it in onBindViewHolder() of RecyclerView adapter is totally wrong.
Why do you need to create an ArrayList of Firebase Datasnapshots? Use the Message class instead (you didn't post Message class structure in your question).
Alter the ChatRecyclerViewAdapter like this
public class ChatRecyclerViewAdapter extends RecyclerView.Adapter<ChatRecyclerViewAdapter.ViewHolder> {
// private ArrayList<String> mMessage = new ArrayList<>(); // comment or remove this line
// private ArrayList<String> mAuthor = new ArrayList<>(); // comment or remove this line
private String mRoomID;
private Context mContext;
private DatabaseReference mDatabaseReference;
// private ArrayList<DataSnapshot> mSnapshotList; // comment or remove this line
private ArrayList<Message> messageList; // add this member
}
The constructor
public ChatRecyclerViewAdapter(Context mContext, ArrayList<String> mMessage, ArrayList<String> mAuthor, String mRoomID, DatabaseReference reference) {
// this.mMessage = mMessage; // comment or remove this line
// this.mAuthor = mAuthor; // comment or remove this line
this.mContext = mContext;
this.mRoomID = mRoomID;
messageList = new ArrayList<>(); // initialize messageList object
mDatabaseReference = reference.child(mRoomID+"_messages");
mDatabaseReference.addChildEventListener(mListener);
}
And inside onChildAdded() method.
#Override
public void onChildAdded(#NonNull DataSnapshot dataSnapshot, #Nullable String s) {
// convert Datasnapshot into a Message object
Message mes = dataSnapshot.getValue(Message.class);
// add it to an ArrayList of Message
messageList.add(mes); // notice the changes
notifyDataSetChanged();
}
Inside onBindViewHolder() method
#Override
public void onBindViewHolder(#NonNull ViewHolder holder, int position) {
// get single Message object from ArrayList
Message mes = messageList.get(position); // notice the difference
// just assuming that you've getter methods in your Message class
// please look into your code
holder.message.setText(mes.getMessage());
holder.author.setText(mes.getAuthor());
}
In getCount() method
#Override
public int getItemCount() {
return messageList.size(); // return the size of the ArrayList
}
Note: The way you implemented Chat using Firebase and RecyclerView is totally wrong. You should use/handle Firebase event listeners in an Activity or Fragment instead of it in an Adapter.
Before going into advanced stuff in Android please learn basic things first. You really need to understand how Firebase and RecyclerView works in first place.
Looking at the code above, ChatRecyclerViewAdapter's getItemCount() method returns the size of the messages array (mMessage.size()). But, notifyDataSetChanged() is called after adding an item to the DataSnapshot arraylist.
You have to also add the message from the snapshot to the messages array for the list to update when you call notifyDataSetChanged().
Also, it is recommended that you avoid calling notifyDataSetChanged() in general for performance reasons. RecyclerView.Adapter has helper methods such as notifyItemInserted or notifyItemRangeInserted to notify the adapter about new additions to the list.
I have an array of username(ids) which i need to search using Firebase Database and rendering using Firebase UI, the way that i am doing it is only showing the last user and not all of the users that have those ids. I need to render the cards or all the users with different ids.
This is my class
public class UserMessageListFragment extends Fragment {
private ProgressDialog progressDialog;
private final String TAG = "UsersMessageList";
private RecyclerView mResultList;
private ArrayList<String> arrayUsers;
public static UserMessageListFragment newInstance() {
return new UserMessageListFragment();
}
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
View view = inflater.inflate(R.layout.fragment_user_message_list, container, false);
mResultList = view.findViewById(R.id.message_list);
mResultList.setHasFixedSize(true);
mResultList.setLayoutManager(new LinearLayoutManager(mResultList.getContext()));
final DatabaseReference refMessages = FirebaseDatabase.getInstance().getReference();
final DatabaseReference ref= FirebaseDatabase.getInstance().getReference().child("usuarios");
refMessages.addChildEventListener(new ChildEventListener() {
#Override
public void onChildAdded(DataSnapshot dataSnapshot, String s) {
if(dataSnapshot.getKey().contains(UserDetails.username+ "_")) {
String[] userChatWithId = dataSnapshot.getKey().split(UserDetails.username+"_");
final Query firebaseSearchQuery = ref.orderByChild("username").equalTo(userChatWithId[1]);
final FirebaseRecyclerOptions<User> options =
new FirebaseRecyclerOptions.Builder<User>()
.setQuery(firebaseSearchQuery, User.class)
.build();
bindAndBuildFirebaseUi(options);
}
}
#Override
public void onChildChanged(DataSnapshot dataSnapshot, String s) {
}
#Override
public void onChildRemoved(DataSnapshot dataSnapshot) {
}
#Override
public void onChildMoved(DataSnapshot dataSnapshot, String s) {
}
#Override
public void onCancelled(DatabaseError databaseError) {
}
});
// progressDialog = new ProgressDialog(getContext());
// progressDialog.setMessage("Carregando...");
// progressDialog.show();
return view;
}
public void bindAndBuildFirebaseUi(FirebaseRecyclerOptions options) {
final FirebaseRecyclerAdapter<User, UsersViewHolder> firebaseRecyclerAdapter = new FirebaseRecyclerAdapter<User, UsersViewHolder>(options) {
#Override
public UsersViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
View v = LayoutInflater.from(parent.getContext()).inflate(R.layout.message_list_layout, parent, false);
return new UsersViewHolder(v);
}
#Override
protected void onBindViewHolder(final UsersViewHolder holder, int position, final User model) {
holder.bind(model);
holder.itemView.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
UserDetails.chatWithId = model.getUsername();
UserDetails.chatWith = model.getName();
startActivity(new Intent(getContext(), Chat.class));
}
});
}
};
firebaseRecyclerAdapter.startListening();
mResultList.setAdapter(firebaseRecyclerAdapter);
}
}
at this line
final Query firebaseSearchQuery = ref.orderByChild("username").equalTo(userChatWithId[1]);
there will be different values inside userChatWithid1, however FirebaseUI is rendering only the last one.
I am starting to hate FirebaseUI because i've been having so many issues with it.
Can anybody help me, please???
You're doing some very unconventional stuff... FirebaseUI will handle all the database listeners and queries for you. All you should do is pass in the root node that contains all your users and the rest will be taken care of. (I believe in your case it's usuarios so ref will do the trick.) I'd recommend reading the docs: https://github.com/firebase/FirebaseUI-Android/blob/master/database/README.md
How do I query SQL IN clause in Firebase Android? I want to use it in a Firebase Recycler adapter to retrieve only some children based on some condition. Something like the following statement:
SQL----> select * from posts where city in(10 cities comes here)
I need a Firebase query to use that in the Firebase Recycler adapter.
The Firebase database does not have the equivalent of SQL's WHERE id IN (1,2,3). In the case of selecting by ID, Firebase's way of retrieving items is equally fast because Firebase pipelines the requests.
Your case is different though, since you're not selecting by ID. Unfortunately there is no way to directly map your query to a equivalent on the Firebase Database.
Instead of trying to make Firebase's NoSQL database do SQL tricks, I highly recommend that you start mapping your data model to something that fits better with a NoSQL database. Some great resources to kick start this process are this article on NoSQL data modeling and our new video series on Firebase for SQL developers.
Also see Firebase complex "contain" queries
I found the solution: we cannot use FirebaseRecyclerAdapter. Instead we have to create custom adapter that extends RecyclerView.ViewHolder.
For passing values to this adapter, first we have to retrieve data using addValueEventListener and then we have to pass values to our adapter.
This is my code...
final ArrayList<Timeline> timelines = new ArrayList<>();
mDatabaseTimeline.addChildEventListener(new ChildEventListener() {
#Override
public void onChildAdded(DataSnapshot dataSnapshot, String s) {
final Timeline timeline = dataSnapshot.getValue(Timeline.class);
if(timeline != null){
mDatabaseFriends.child(mAuth.getCurrentUser().getUid()).child("active").addListenerForSingleValueEvent(new ValueEventListener() {
#Override
public void onDataChange(DataSnapshot dataSnapshot) {
if (mAuth.getCurrentUser().getUid().equals(timeline.getUid()) || dataSnapshot.hasChild(timeline.getUid())) {
timelines.add(timeline);
mTimelineRecycler.setAdapter(new RecyclerAdapter(TimelineFragment.this.getContext(), timelines));
}
}
#Override
public void onCancelled(DatabaseError databaseError) {
}
});
}
}
#Override
public void onChildChanged(DataSnapshot dataSnapshot, String s) {
}
#Override
public void onChildRemoved(DataSnapshot dataSnapshot) {
}
#Override
public void onChildMoved(DataSnapshot dataSnapshot, String s) {
}
#Override
public void onCancelled(DatabaseError databaseError) {
}
});
adapter----->
public class RecyclerAdapter extends RecyclerView.Adapter<RecyclerView.ViewHolder> {
Context context;
ArrayList<Timeline> timeline;
public RecyclerAdapter(Context context, ArrayList<Timeline> timeline) {
this.context = context;
this.timeline = timeline;
}
#Override
public RecyclerView.ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
LayoutInflater inflater = LayoutInflater.from(context);
View row = inflater.inflate(R.layout.timeline_row, parent, false);
TimelineViewHolder holder = new TimelineViewHolder(row);
return holder;
}
#Override
public void onBindViewHolder(RecyclerView.ViewHolder holder, int position) {
final String post_key = timeline.get(position).getPostkey();
((TimelineViewHolder) holder).setUsername(timeline.get(position).getUsername());
}
#Override
public int getItemCount() {
return timeline.size();
}
public class TimelineViewHolder extends RecyclerView.ViewHolder {
public TimelineViewHolder(View itemView) {
super(itemView);
view = itemView;
}
public View getView() {
return view;
}
public void setUsername(String username) {
TextView usernameTxtView = (TextView) view.findViewById(R.id.timeline_username);
usernameTxtView.setText(username);
}
}
}