Android/Firebase realtime-database how get only last message? - android

I'm using the firebase Database at the Android Studio. Code java. I use realtime database.
I'm doing a Chat app. I want to show users the last message in their inbox.
I have this database:
message: {
User uıd: {
Uid of the person he is talking to: {
random key: {
-date
-from
-message
-time
-type
}
}
}
I have ref to database als:
mAuth = FirebaseAuth.getInstance();
currentUserID = mAuth.getCurrentUser().getUid();
ChatsRef=FirebaseDatabase.getInstance().getReference().child("message").child(currentUserID);
I'm using this to get :
public void messageegetir(){
FirebaseRecyclerOptions<Messages> options =
new FirebaseRecyclerOptions.Builder<Messages>()
.setQuery(ChatsRef,Messages.class)
.build();
FirebaseRecyclerAdapter<Messages, ChatsViewHolder> adapter =
new FirebaseRecyclerAdapter<Messages, ChatsViewHolder>(options) {
#Override
protected void onBindViewHolder(#NonNull final ChatsViewHolder holder, final int position, #NonNull final Messages model) {
final String usersIDs = getRef(position).getKey();
final String[] retImage = {"default_image"};
}
#NonNull
#Override
public ChatsViewHolder onCreateViewHolder(#NonNull ViewGroup viewGroup, int i) {
View view = LayoutInflater.from(viewGroup.getContext()).inflate(R.layout.message_list_model,viewGroup,false);
return new ChatsViewHolder(view);
}
};
chatlist.setAdapter(adapter);
adapter.startListening();
updateUserStatus("online");
}
my publıc statıc class :
public static class ChatsViewHolder extends RecyclerView.ViewHolder{
CircleImageView profileImage ;
ImageView onlinestatus;
TextView lastmessage , userName ;
public ChatsViewHolder(#NonNull View itemView) {
super(itemView);
profileImage =itemView.findViewById(R.id.messageprofileimageee);
userName =itemView.findViewById(R.id.messagenameee);
lastmessage =itemView.findViewById(R.id.messageinfooo);
onlinestatus =itemView.findViewById(R.id.onlinestatus);
}
}
Messages class :
public class Messages {
public String data, time, type, message, from ;
public Messages(){
}
public Messages(String data, String time, String type, String message, String from) {
this.data = data;
this.time = time;
this.type = type;
this.message = message;
this.from = from;
}
public String getData() {
return data;
}
public void setData(String data) {
this.data = data;
}
public String getTime() {
return time;
}
public void setTime(String time) {
this.time = time;
}
public String getType() {
return type;
}
public void setType(String type) {
this.type = type;
}
public String getMessage() {
return message;
}
public void setMessage(String message) {
this.message = message;
}
public String getFrom() {
return from;
}
public void setFrom(String from) {
this.from = from;
}
}
enter image description here
How can I get those data and write them in a textview?

i suggest that you modify your database structure , denormalize it like it is recommended by firebase docs. see the link https://firebase.google.com/docs/database/android/structure-data#best_practices_for_data_structure
And you will understand

I did a chat app and the way I did it is that I have two main roots and one is dedicated to getting the last sent message and it updated every time a new message is received and the other root is dedicated to storing a list of all messages between two users so I suggest doing something similar.

Related

How do I make readable TimeStamp from Cloud Firestore?

So below are the database of my cloud firestore. That DatePosted shows 2nd December, 2019 at 8.19 pm UTC +8. According to the code I used and I run my app, it shows an unreadable number. Is it correct on how I retrieve the data from cloud firebase? If its wrong, how do I retrieve that timestamp and make it readable?
ForumAdapter.java
public class ForumAdapter extends FirestoreRecyclerAdapter<Forum,ForumAdapter.ForumHolder> {
private OnItemClickListener listener;
public ForumAdapter(FirestoreRecyclerOptions<Forum> options) {
super(options);
}
#Override
public void onBindViewHolder(ForumHolder forumHolder, int i, Forum forum) {
forumHolder.textViewTitle.setText(forum.getTitle());
forumHolder.textViewDescription.setText(forum.getDescription());
forumHolder.timeStamp.setText(forum.getDatePosted().toString());
}
#NonNull
#Override
public ForumHolder onCreateViewHolder(#NonNull ViewGroup parent, int viewType) {
android.view.View v = LayoutInflater.from(parent.getContext()).inflate(R.layout.cardviewforumtitle,parent,false);
return new ForumHolder(v);
}
class ForumHolder extends RecyclerView.ViewHolder{
TextView textViewTitle;
TextView textViewDescription;
TextView timeStamp;
public ForumHolder(View itemView) {
super(itemView);
textViewTitle = itemView.findViewById(R.id.tvTitle);
textViewDescription = itemView.findViewById(R.id.tvDescription);
timeStamp = itemView.findViewById(R.id.tvTimestamp);
textViewTitle.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
int position = getAdapterPosition();
// NO_POSITION to prevent app crash when click -1 index
if(position != RecyclerView.NO_POSITION && listener !=null ){
listener.onItemClick(getSnapshots().getSnapshot(position),position);
}
}
});
}
}
public interface OnItemClickListener{
void onItemClick(DocumentSnapshot documentSnapshot, int position);
}
public void setOnItemClickListener(OnItemClickListener listener){
this.listener = listener;
}
#Override
public int getItemCount() {
return super.getItemCount();
}
}
Forum.java
public class Forum {
private String Title;
private String Description;
private String User;
private com.google.firebase.Timestamp DatePosted;
public Forum() {
}
public Forum(String title, String description, Timestamp datePosted,String user) {
Title = title;
Description = description;
DatePosted = datePosted;
User = user;
}
public String getUser() {
return User;
}
public void setUser(String user) {
User = user;
}
public String getTitle() {
return Title;
}
public void setTitle(String title) {
Title = title;
}
public String getDescription() {
return Description;
}
public void setDescription(String description) {
Description = description;
}
public Timestamp getDatePosted() {
return DatePosted;
}
public void setDatePosted(Timestamp datePosted) {
DatePosted = datePosted;
}
}
When you query a document with a timestamp field, you will get a Timestamp object back. If you'd rather have a Date object, you can use its toDate method.
You will need to write some code to format this for display. This is a very common task for mobile and web apps.

How do I access the item in FirebaseRecycler's getItemViewType()?

I am building a chat functionality within an app. The messages sent by user will be on the right side and messages received by the user on left side of the screen. All the chat data is stored in a pojo. In FirebaseRecycler#getItemViewType() method I want to compare the UID of the current item/pojo with mFirebaseUser.getUid() and assign the layout accordingly.
How do I access the item within the getItemViewType()?
pojo message
public class message {
private String id;
private String text;
private String name;
private String photoUrl;
private String imageUrl;
private String uid;
public message() {
}
public message(String text, String name, String photoUrl, String imageUrl, String uid) {
this.text = text;
this.name = name;
this.photoUrl = photoUrl;
this.imageUrl = imageUrl;
this.uid = uid;
}
public String getId() {
return id;
}
public void setId(String id) {
this.id = id;
}
public void setText(String text) {
this.text = text;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getPhotoUrl() {
return photoUrl;
}
public String getText() {
return text;
}
public void setPhotoUrl(String photoUrl) {
this.photoUrl = photoUrl;
}
public String getImageUrl() {
return imageUrl;
}
public void setImageUrl(String imageUrl) {
this.imageUrl = imageUrl;
}
public void setUid(String uid) {
this.uid = uid;
}
public String getUid() {
return uid;
}
}
FirebaseRecyler Method.
private void getMessages() {
final int VIEW_TYPE_MESSAGE_SENT = 1;
final int VIEW_TYPE_MESSAGE_RECEIVED = 2;
FirebaseRecyclerOptions<message> options =
new FirebaseRecyclerOptions.Builder<message>()
.setQuery(messagesRef, parser)
.build();
mFirebaseAdapter = new FirebaseRecyclerAdapter<message, RecyclerView.ViewHolder>(options) {
#Override
public int getItemViewType(int position) {
if (mFirebaseUser.getUid() == ?) {
// If the current user is the sender of the message
// Based on the UID associated with the message and current UID
return VIEW_TYPE_MESSAGE_SENT;
} else {
// If some other user sent the message
return VIEW_TYPE_MESSAGE_RECEIVED;
}
}
#Override
#NonNull
public RecyclerView.ViewHolder onCreateViewHolder(#NonNull ViewGroup viewGroup, int viewType) {
if(viewType == VIEW_TYPE_MESSAGE_SENT) {
LayoutInflater inflater = LayoutInflater.from(viewGroup.getContext());
return new SentMessageViewHolder(inflater.inflate(R.layout.sent_item_message, viewGroup, false));
} else if(viewType == VIEW_TYPE_MESSAGE_RECEIVED) {
LayoutInflater inflater = LayoutInflater.from(viewGroup.getContext());
return new MessageViewHolder(inflater.inflate(R.layout.item_message, viewGroup, false));
}
return null;
}
#Override
protected void onBindViewHolder(RecyclerView.ViewHolder viewHolder,
int position,
#NonNull message friendlyMessage) {
mProgressBar.setVisibility(ProgressBar.INVISIBLE);
switch (viewHolder.getItemViewType()) {
case VIEW_TYPE_MESSAGE_RECEIVED:
((MessageViewHolder) viewHolder).bind(friendlyMessage);
break;
case VIEW_TYPE_MESSAGE_SENT:
((SentMessageViewHolder) viewHolder).bind(friendlyMessage);
break;
}
}
};
mFirebaseAdapter.registerAdapterDataObserver(new RecyclerView.AdapterDataObserver() {
....
});
}
Let try this,
if (mFirebaseUser.getUid() == options.get(position). getUid())
The question is how to access the item within getViewItemType(). For that use the getItem(position) method.
#Override
public int getItemViewType(int position) {
if (mFirebaseUser.getUid() == getItem(position).getUid()) {
// If the current user is the sender of the message
// Based on the UID associated with the message and current UID
return VIEW_TYPE_MESSAGE_SENT;
} else {
// If some other user sent the message
return VIEW_TYPE_MESSAGE_RECEIVED;
}
}
The solution was quite simple as pointed out by other answers.
The only problem with the other two answers were condition checking in if statement, which showed the sent message on right only till the page got refreshed. The solution was to use equals() method from TextUtils class.
#Override
public int getItemViewType(int position) {
if (TextUtils.equals(mFirebaseUser.getUid(), getItem(position).getUid())) {
// If the current user is the sender of the message
return VIEW_TYPE_MESSAGE_SENT;
} else {
// If some other user sent the message
return VIEW_TYPE_MESSAGE_RECEIVED;
}
}

Recycler View Adding Previous Content On New Contents

Thanks for the help as always. I am making a firebase chat app and i ran into this bug and i can figure out what is happening.
Usually if i clear the database and start fresh, the error doesnt occur but
Whenever i send a message, an older received message is included in the new one in the recyclerview. i am lost and frustrated. I have searched through stackoverflow for solution to no positive result. Here is a screenshot of the error.
private void loadMessages() {
chatMessagesRef = db.getReference("ChatMessages").child(Common.currentUser.getMatric()).child(user_id);
adapter = new FirebaseRecyclerAdapter<Message, ChatMessageViewHolder>(
Message.class,
R.layout.single_message_item,
ChatMessageViewHolder.class,
chatMessagesRef
) {
#Override
protected void populateViewHolder(final ChatMessageViewHolder viewHolder, final Message model, int position) {
if (model.getFrom().equalsIgnoreCase(Common.currentUser.getMatric())) {
if (model.getType().equalsIgnoreCase("text")){
viewHolder.yourMessage.setText(model.getMessage());
viewHolder.yourMessage.setVisibility(View.VISIBLE);
viewHolder.theAll.setBackgroundColor(Color.WHITE);
}
} else if (model.getFrom().equalsIgnoreCase(user_id)){
if (model.getType().equalsIgnoreCase("text")){
viewHolder.messageText.setText(model.getMessage());
viewHolder.messageText.setVisibility(View.VISIBLE);
viewHolder.theAll.setBackgroundColor(Color.YELLOW);
}
}
}
};
messagesRecycler.setAdapter(adapter);
adapter.notifyDataSetChanged();
messagesRecycler.scrollToPosition(adapter.getItemCount() - 1);
adapter.cleanup();
}
private void sendTheMessage() {
String message = chatBox.getText().toString();
if (message.isEmpty()){
} else {
long date = System.currentTimeMillis();
messageRef = db.getReference("ChatMessages").child(Common.currentUser.getMatric()).child(user_id).push();
final String chatMessageId = messageRef.getKey();
final Message newMessage = new Message(message, "text", date, false, Common.currentUser.getMatric());
messageRef2 = db.getReference("ChatMessages").child(Common.currentUser.getMatric()).child(user_id);
messageRef2.child(chatMessageId).setValue(newMessage).addOnSuccessListener(new OnSuccessListener<Void>() {
#Override
public void onSuccess(Void aVoid) {
messageRef3 = db.getReference("ChatMessages").child(user_id).child(Common.currentUser.getMatric());
messageRef3.child(chatMessageId).setValue(newMessage);
sendNotification();
chatBox.setText("");
}
});
}
}
public class Message {
private String message, type;
private long time;
private boolean seen;
private String from;
public Message() {
}
public Message(String message, String type, long time, boolean seen, String from) {
this.message = message;
this.type = type;
this.time = time;
this.seen = seen;
this.from = from;
}
public String getMessage() {
return message;
}
public void setMessage(String message) {
this.message = message;
}
public String getType() {
return type;
}
public void setType(String type) {
this.type = type;
}
public long getTime() {
return time;
}
public void setTime(long time) {
this.time = time;
}
public boolean isSeen() {
return seen;
}
public void setSeen(boolean seen) {
this.seen = seen;
}
public String getFrom() {
return from;
}
public void setFrom(String from) {
this.from = from;
}
}This is the database structure

unable to retrieve data from one app to another app from firebase single Database

I have 2 applications(different package names) which use one Firebase database. One app has to write access to the database and another have read access to the database.in my second application, i use recyclerview to retrieve data which is stored by 1st App.
for this I use below code:
FirebaseOptions options = new FirebaseOptions.Builder()
.setApplicationId("1:567....259c8f58311") // Required for Analytics.
.setApiKey("AIzaSyA9BRxl......hE03y5qD-c") // Required for Auth.
.setDatabaseUrl("https://mycity-3a561.firebaseio.com/") // Required for RTDB.
.build();
FirebaseApp.initializeApp(this /* Context */, options, "MyCity");
// Retrieve my other app.
FirebaseApp app = FirebaseApp.getInstance("MyCity");
// Get the database for the other app.
FirebaseDatabase secondaryDatabase = FirebaseDatabase.getInstance(app);
DatabaseReference data = secondaryDatabase.getInstance().getReference();
data.addValueEventListener(new ValueEventListener() {
#Override
public void onDataChange(DataSnapshot snapshot) {
for (DataSnapshot ds : snapshot.getChildren()) {
for (DataSnapshot dSnapshot : ds.getChildren()) {
WaterClass waterClass = dSnapshot.getValue(WaterClass.class);
Log.d("Show", waterClass.getName() == null ? "" : waterClass.getName());
list.add(waterClass);
}
adapter = new WaterAdapter(ShowWaterDetails.this, list);
recyclerView.setAdapter(adapter);
adapter.notifyDataSetChanged();
progressDialog.dismiss();
}
}
#Override
public void onCancelled(DatabaseError databaseError) {
progressDialog.dismiss();
}
});
}
Adapter class
private class WaterAdapter extends RecyclerView.Adapter<WaterAdapter.ViewHolder> {
ShowWaterDetails showDetail;
List<WaterClass> listData;
public WaterAdapter(ShowWaterDetails showWaterDetails, List<WaterClass> list) {
this.showDetail = showWaterDetails;
this.listData = list;
}
#Override
public ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
View view = LayoutInflater.from(parent.getContext()).inflate(R.layout.show_items, parent, false);
WaterAdapter.ViewHolder viewHolder = new WaterAdapter.ViewHolder(view);
return viewHolder;
}
#Override
public void onBindViewHolder(WaterAdapter.ViewHolder holder, int position) {
WaterClass AllDetails = listData.get(position);
holder.NameTextView.setText(AllDetails.getName());
holder.DetailTextView.setText(AllDetails.getDetail());
holder.DateTextView.setText(AllDetails.getDate());
holder.LocationTextView.setText(AllDetails.getLocation());
holder.TypeTextView.setText(AllDetails.getType());
Picasso.with(showDetail).load(AllDetails.getImgurl()).resize(120, 60).into(holder.ImageTextView);
}
#Override
public int getItemCount() {
return listData.size();
}
class ViewHolder extends RecyclerView.ViewHolder {
public TextView NameTextView;
public TextView DetailTextView;
public TextView DateTextView;
public TextView LocationTextView;
public TextView TypeTextView;
public ImageView ImageTextView;
public ViewHolder(View itemView) {
super(itemView);
NameTextView = itemView.findViewById(R.id.ShowNameTextView);
DetailTextView = itemView.findViewById(R.id.ShowDetailTextView);
DateTextView = itemView.findViewById(R.id.ShowDateTextView);
LocationTextView = itemView.findViewById(R.id.ShowLocationTextView);
TypeTextView = itemView.findViewById(R.id.ShowTypeTextView);
ImageTextView = itemView.findViewById(R.id.ShowImageView);
}
}
}
}
POJO Class
class WaterClass {
private String id;
private String email;
private String name;
private String type;
private String detail;
private String location;
private String date;
private String imgurl;
public WaterClass(){
}
public WaterClass(String id, String currentUserString, String imageUrl, String nameString, String typeString, String detailString, String locationString, String dateString) {
this.id = id;
this.email = currentUserString;
this.name =nameString;
this.type = typeString;
this.detail = detailString;
this.location = locationString;
this.date = dateString;
this.imgurl = imageUrl;
}
public String getImgurl() {
return imgurl;
}
public void setImgurl(String imgurl) {
this.imgurl = imgurl;
}
public String getId() {
return id;
}
public void setId(String id) {
this.id = id;
}
public String getEmail() {
return email;
}
public void setEmail(String email) {
this.email = email;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getType() {
return type;
}
public void setType(String type) {
this.type = type;
}
public String getDetail() {
return detail;
}
public void setDetail(String detail) {
this.detail = detail;
}
public String getLocation() {
return location;
}
public void setLocation(String location) {
this.location = location;
}
public String getDate() {
return date;
}
public void setDate(String date) {
this.date = date;
}
}
:
there is no error but my recycler not showing anything
go to onStart() and start listening
#Override
protected void onStart() {
super.onStart();
adapter.startListening();
}
and in your onStop
#Override
protected void onStop() {
super.onStop();
adapter.stopListening();
}
The FirebaseRecyclerAdapter uses a snapshot listener to monitor changes to the Firestore query. To begin listening for data, call the startListening() method. You may want to call this in your onStart() method. Make sure you have finished any authentication necessary to read the data before calling startListening() or your query will fail.
Be sure that the names of constant in the POJO match exatly the names
of your database structure in your firebase console !!
ps: do not post your api-keys or app-ids in your questions, keep them secret, and consider using firebaserecycleradapter if you are using firebase-database , it will be more easy to setup and to show values.
Your POJO is ok !
Found Solution!!
just change this part of a code
FirebaseApp.initializeApp(this /* Context */, options, "MyCity");
// Retrieve my other app.
FirebaseApp app = FirebaseApp.getInstance("MyCity");
TO
FirebaseApp.initializeApp(this);
// Retrieve my other app.
FirebaseApp app = FirebaseApp.getInstance("[DEFAULT]");

Firebase add item for user

I'm working on a project with android and firebase real-time database.
I'm not really sure how to achieve this structure for my project.
I have a list of Users (with name, email etc).
I want to add one/or multiple item(s) for a single user.
So User1 can have:
Item1(color: Black, percentage: 90 etc etc)
Item2(...)
I am not sure if this is the correct way to structure the data or if there is a better way.
Firebase structure
And I should be able to get all items for this user and show them in a listview.
Any help how to achieve this.
I would advice you to work with RecyclerView.
The following example is used as a chat:
Firstly create your ViewHolder and Data class:
public static class FirechatMsgViewHolder extends RecyclerView.ViewHolder {
TextView userTextView;
TextView emailUserTextView;
TextView msgTextView;
CircleImageView userImageView;
public FirechatMsgViewHolder(View v) {
super(v);
userTextView = (TextView) itemView.findViewById(R.id.userTextView);
emailUserTextView = (TextView) itemView.findViewById(R.id.emailUserTextView);
msgTextView = (TextView) itemView.findViewById(R.id.msgTextView);
userImageView = (CircleImageView) itemView.findViewById(R.id.userImageView);
}
}
Data Class:
public class ChatMessage {
private String text;
private String name;
private String email;
private String photoUrl;
public ChatMessage() {
}
public ChatMessage(String name, String email, String text, String photoUrl) {
this.text = text;
this.name = name;
this.photoUrl = photoUrl;
this.email = email;
}
public String getText() {
return text;
}
public void setText(String text) {
this.text = text;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getEmail() {
return email;
}
public void setEmail(String email) {
this.email = email;
}
public String getPhotoUrl() {
return photoUrl;
}
public void setPhotoUrl(String photoUrl) {
this.photoUrl = photoUrl;
}
}
Then add these fields into the ChatActivity:
private DatabaseReference mSimpleFirechatDatabaseReference;
private FirebaseRecyclerAdapter<ChatMessage, FirechatMsgViewHolder>
mFirebaseAdapter;
Then init all fields in your onCreate + set adapter:
//Create the reference to get data from Firebase.
mSimpleFirechatDatabaseReference = FirebaseDatabase.getInstance().getReference();
//Fill the adapter with data + add all required listeners
mFirebaseAdapter = new FirebaseRecyclerAdapter<ChatMessage,
FirechatMsgViewHolder>(
ChatMessage.class,
R.layout.chat_message,
FirechatMsgViewHolder.class,
mSimpleFirechatDatabaseReference.child("messages")) {
#Override
protected void populateViewHolder(FirechatMsgViewHolder viewHolder, ChatMessage friendlyMessage, int position) {
mProgressBar.setVisibility(ProgressBar.INVISIBLE);
viewHolder.userTextView.setText(friendlyMessage.getName());
viewHolder.emailUserTextView.setText(friendlyMessage.getEmail());
viewHolder.msgTextView.setText(friendlyMessage.getText());
if (friendlyMessage.getPhotoUrl() == null) {
viewHolder.userImageView
.setImageDrawable(ContextCompat
.getDrawable(ChatActivity.this,
R.drawable.profile));
} else {
Glide.with(ChatActivity.this)
.load(friendlyMessage.getPhotoUrl())
.into(viewHolder.userImageView);
}
}
};
mFirebaseAdapter.registerAdapterDataObserver(new RecyclerView.AdapterDataObserver() {
#Override
public void onItemRangeInserted(int positionStart, int itemCount) {
super.onItemRangeInserted(positionStart, itemCount);
int chatMessageCount = mFirebaseAdapter.getItemCount();
int lastVisiblePosition =
mLinearLayoutManager.findLastCompletelyVisibleItemPosition();
if (lastVisiblePosition == -1 ||
(positionStart >= (chatMessageCount - 1) &&
lastVisiblePosition == (positionStart - 1))) {
mMessageRecyclerView.scrollToPosition(positionStart);
}
}
});
How to send data to Firebase
// The way to send data to the database. Add any required path!
mSendButton.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View view) {
ChatMessage friendlyMessage = new
ChatMessage(mUsername,
mUseremail,
"Some text",
mPhotoUrl);
mSimpleFirechatDatabaseReference.child("messages")
.push().setValue(friendlyMessage);
}
});
You should structure your database as shown in below image. With this structure, you can get all items for a particular User and easily show them in ListView.

Categories

Resources