So, I am using Firebase UI to get data from Database.
It looks like this:
I want to iterate through "messages" to get every child, and show it as message at my app. This is how my UserMessage class looks alike:
public class UserMessage {
private String mUserLogin;
private String mUserMessage;
private String mUID;
UserMessage(String userLogin, String userMessage, String uid) {
mUserLogin = userLogin;
mUserMessage = userMessage;
mUID = uid;
}
public String getmUserLogin() {
return mUserLogin;
}
public void setmUserLogin(String mUserLogin) {
this.mUserLogin = mUserLogin;
}
public String getmUserMessage() {
return mUserMessage;
}
public String getmUID() {
return mUID;
}
public void setmUID(String mUID) {
this.mUID = mUID;
}
public void setmUserMessage(String mUserMessage) {
this.mUserMessage = mUserMessage;
}
}
And i want to get it through FirebaseRecyclerOptions:
FirebaseRecyclerOptions<UserMessage> options =
new FirebaseRecyclerOptions.Builder<UserMessage>()
.setQuery(firebaseDatabaseModel.getQuery(), new SnapshotParser<UserMessage>() {
@NonNull
@Override
public UserMessage parseSnapshot(@NonNull DataSnapshot snapshot) {
Log.d("snapshot length", String.valueOf(snapshot.getChildrenCount()));
return snapshot.getValue(UserMessage.class);
}
})
.build();
And here is how my firebaseDatabaseModel.getQuery() method looks like:
public Query getQuery() {
DatabaseReference messageReference = database.child("messages");
return messageReference.limitToLast(50);
}
And this is how I want to set data in my FirebaseRecyclerAdapter
class ChatMessagesAdapter extends FirebaseRecyclerAdapter<UserMessage, ChatMessagesAdapter.ChatHolder> {
private UserMessage[] userMessages;
/**
* Initialize a {@link RecyclerView.Adapter} that listens to a Firebase query. See
* {@link FirebaseRecyclerOptions} for configuration options.
*
* @param options
*/
public ChatMessagesAdapter(@NonNull FirebaseRecyclerOptions<UserMessage> options) {
super(options);
userMessages = (UserMessage[]) options.getSnapshots().toArray();
}
@Override
protected void onBindViewHolder(@NonNull ChatHolder holder, int position, @NonNull UserMessage model) {
holder.message.setText(userMessages[position].getmUserMessage());
holder.user.setText(userMessages[position].getmUserLogin());
}
@NonNull
@Override
public ChatHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) {
View view = LayoutInflater.from(parent.getContext()).inflate(R.layout.chat_message, parent, false);
return new ChatHolder(view);
}
static class ChatHolder extends RecyclerView.ViewHolder {
@BindView(R.id.user_message)
TextView message;
@BindView(R.id.user_login)
TextView user;
private ChatHolder(View itemView) {
super(itemView);
ButterKnife.bind(itemView);
}
}
}
The thing is, not matter how I'm trying to send options (User Messages) through array to FirebaseRecyclerAdapter, it always has 0 count. Probably the problem is lying under custom parser (I have to compose it properly), but my debugger is just skipping this part of code:
public UserMessage parseSnapshot(@NonNull DataSnapshot snapshot) {
Log.d("snapshot length", String.valueOf(snapshot.getChildrenCount()));
return snapshot.getValue(UserMessage.class);
}
So I cannot even check what I'm doing wrong here. I've tried to figure it out for few hours already, and I just really don't know how to deal with it.
//Edit 1:
Due to @Alex Malmo suggestions, I've changed database keys to:
And UserMessage.class to:
public class UserMessage {
private String userLogin, userMessage, uid;
public UserMessage() {}
public UserMessage(String userLogin, String userMessage, String uid) {
this.userLogin = userLogin;
this.userMessage = userMessage;
this.uid = uid;
}
public String getUserLogin() { return userLogin; }
public String getUserMessage() { return userMessage; }
public String getUid() { return uid; }
}
It looks like the thing is still in FirebaseRecyclerOptions creation. I've tried those two methods:
FirebaseRecyclerOptions<UserMessage> options = new FirebaseRecyclerOptions.Builder<UserMessage>()
.setQuery(query,
UserMessage.class)
.build();
and
FirebaseRecyclerOptions<UserMessage> options = new FirebaseRecyclerOptions.Builder<UserMessage>()
.setQuery(query,
new SnapshotParser<UserMessage>() {
@NonNull
@Override
public UserMessage parseSnapshot(@NonNull DataSnapshot snapshot) {
return snapshot.getValue(UserMessage.class);
}
})
.build();
In both cases - second argument in setQuery method (parsing part) seems to be ignored (compilator just skips that part - it gets correct query, and goes straight to .build()), which seems to be a whole problem with empty data in adapter.
Okay, I have finally resolved it. The problem was, that I've completely misunderstood FirebaseRecyclerOptions functions. I was completely sure that it's passing data inside it, and whole thing was that I was trying to get that data, without letting whole method do its work.
So I have changed adapter construction from:
class ChatMessagesAdapter extends FirebaseRecyclerAdapter<UserMessage, ChatMessagesAdapter.ChatHolder> {
private UserMessage[] userMessages;
/**
* Initialize a {@link RecyclerView.Adapter} that listens to a Firebase query. See
* {@link FirebaseRecyclerOptions} for configuration options.
*
* @param options
*/
public ChatMessagesAdapter(@NonNull FirebaseRecyclerOptions<UserMessage> options) {
super(options);
userMessages = (UserMessage[]) options.getSnapshots().toArray();
}
@Override
protected void onBindViewHolder(@NonNull ChatHolder holder, int position, @NonNull UserMessage model) {
holder.message.setText(userMessages[position].getmUserMessage());
holder.user.setText(userMessages[position].getmUserLogin());
}
@NonNull
@Override
public ChatHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) {
View view = LayoutInflater.from(parent.getContext()).inflate(R.layout.chat_message, parent, false);
return new ChatHolder(view);
}
static class ChatHolder extends RecyclerView.ViewHolder {
@BindView(R.id.user_message)
TextView message;
@BindView(R.id.user_login)
TextView user;
private ChatHolder(View itemView) {
super(itemView);
ButterKnife.bind(itemView);
}
}
To:
class ChatMessagesAdapter extends FirebaseRecyclerAdapter<UserMessage, ChatMessagesAdapter.ChatHolder> {
private ArrayList<UserMessage> messagesList = new ArrayList<>();
/**
* Initialize a {@link RecyclerView.Adapter} that listens to a Firebase query. See
* {@link FirebaseRecyclerOptions} for configuration options.
*
* @param options
*/
ChatMessagesAdapter(@NonNull FirebaseRecyclerOptions<UserMessage> options) {
super(options); }
@Override
protected void onBindViewHolder(@NonNull ChatHolder holder, int position, @NonNull UserMessage model) {
messagesList.add(model);
holder.message.setText(messagesList.get(position).getUserMessage());
holder.user.setText(messagesList.get(position).getUserLogin());
}
@NonNull
@Override
public ChatHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) {
View view = LayoutInflater.from(parent.getContext()).inflate(R.layout.chat_message, parent, false);
return new ChatHolder(this,view);
}
static class ChatHolder extends RecyclerView.ViewHolder {
@BindView(R.id.user_message)
TextView message;
@BindView(R.id.user_login)
TextView user;
private ChatHolder(ChatMessagesAdapter chatMessagesAdapter, View itemView) {
super(itemView);
ButterKnife.bind(this, itemView);
}
}
}
And it works perfectly fine. I've based that on this example: https://www.programcreek.com/java-api-examples/?code=panzerama/Dispatch/Dispatch-master/app/src/main/java/com/indexyear/jd/dispatch/activities/DispatchTeamActivity.java
So if you would have any problem with whole FirebaseUI thing, the above is proper example in my opinion.
Thanks to @Alex Malmo and @Yupi for suggestions!