I am building a Chat application using Firebase database. I have been able send and receive chats, I have also been able to get the users contacted under java class ChatsActivty The problem is that the users in my ChatsActivity are only ordered alphabetically even when a new message is sent or received ie onDataChange, the list remains the same. I want user latest contacted to appear on top every time a message is sent or received.
My code is as shown below:
ChatsActivity.java
public class ChatsActivity extends AppCompatActivity {
private RecyclerView chatsRecyclerview;
private AdapterUsers userAdapter;
private List<ModelUser> mUsers;
FirebaseUser fUser;
DatabaseReference reference;
private List<String> userList;
@Override
protected void onCreate(@Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_chats);
ActionBar actionBar = getSupportActionBar();
actionBar.setTitle("Messages");
actionBar.setDisplayHomeAsUpEnabled(true);
chatsRecyclerview = findViewById(R.id.chats_recyclerview);
//Linear Layout for RecyclerView
LinearLayoutManager linearLayoutManager = new LinearLayoutManager(ChatsActivity.this);
//recyclerview properties
chatsRecyclerview.setHasFixedSize(true);
chatsRecyclerview.setLayoutManager(linearLayoutManager);
fUser = FirebaseAuth.getInstance().getCurrentUser();
userList = new ArrayList<>();
reference = FirebaseDatabase.getInstance().getReference("Chats");
Query query = reference.orderByKey().limitToLast(10000);
query.addValueEventListener(new ValueEventListener() {
@Override
public void onDataChange(@NonNull DataSnapshot snapshot) {
userList.clear();
for (DataSnapshot dataSnapshot : snapshot.getChildren()) {
ModelChat chat = dataSnapshot.getValue(ModelChat.class);
if (chat.getSender().equals(fUser.getUid())) {
userList.add(chat.getReceiver());
}
if (chat.getReceiver().equals(fUser.getUid())) {
userList.add(chat.getSender());
}
}
readChats();
}
@Override
public void onCancelled(@NonNull DatabaseError error) {
}
});
}
private void readChats() {
mUsers = new ArrayList<>();
reference = FirebaseDatabase.getInstance().getReference("Users");
reference.addValueEventListener(new ValueEventListener() {
@Override
public void onDataChange(@NonNull DataSnapshot snapshot) {
mUsers.clear();
for (DataSnapshot ds : snapshot.getChildren()) {
ModelUser user = ds.getValue(ModelUser.class);
for (String uid : userList) {
assert user != null;
if (user.getUid().equals(uid)) {
mUsers.add(user);
break;
}
}
}
userAdapter = new AdapterUsers(ChatsActivity.this, mUsers);
chatsRecyclerview.setAdapter(userAdapter);
}
@Override
public void onCancelled(@NonNull DatabaseError error) {
}
});
}
@Override
public boolean onOptionsItemSelected(@NonNull MenuItem item) {
if (item.getItemId() == android.R.id.home) {
startActivity(new Intent(ChatsActivity.this, HomeActivity.class));
ChatsActivity.this.finish();
}
return super.onOptionsItemSelected(item);
}
}
My AdapterUsers code:
public class AdapterUsers extends RecyclerView.Adapter<AdapterUsers.MyHolder>{
Context context;
List<ModelUser> userList;
//Constructor > Generate
public AdapterUsers(Context context, List<ModelUser> userList) {
this.context = context;
this.userList = userList;
}
@NonNull
@Override
public MyHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) {
//Inflate layout (row_user)
View view = LayoutInflater.from(parent.getContext()).inflate(R.layout.row_users, parent, false);
return new MyHolder(view);
}
@Override
public void onBindViewHolder(@NonNull MyHolder holder, int position) {
//get data
String userUID = userList.get(position).getUid();
String userProfilePic = userList.get(position).getProfilepic();
String userName = userList.get(position).getFirstname() + " " + userList.get(position).getLastname();
String userNickname = userList.get(position).getNickname();
String userStatus = userList.get(position).getStatus();
//set data
holder.mNameTv.setText(userName);
holder.mNicknameTv.setText(userNickname);
holder.mStatusTv.setText(userStatus);
Glide
.with(context)
.load(userProfilePic)
.apply(RequestOptions.circleCropTransform())
.into(holder.mAvatarIv);
//Handle item click
holder.itemView.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
/*Click user from user list to start conversation
*Start Activity by putting UID of receiver
*we will use that UID to identify the user we are gonna chat */
Intent intent = new Intent(context, ChatActivity.class);
intent.putExtra("userUid", userUID);
context.startActivity(intent);
}
});
}
@Override
public int getItemCount() {
return userList.size();
}
class MyHolder extends RecyclerView.ViewHolder {
ImageView mAvatarIv;
TextView mNameTv, mNicknameTv, mStatusTv;
public MyHolder(@NonNull View itemView) {
super(itemView);
mAvatarIv = itemView.findViewById(R.id.avatarIv);
mNameTv = itemView.findViewById(R.id.nameTv);
mNicknameTv = itemView.findViewById(R.id.nicknameTv);
mStatusTv = itemView.findViewById(R.id.statusTv);
mStatusTv.setEllipsize(TextUtils.TruncateAt.MARQUEE);
mStatusTv.setSelected(true);
mStatusTv.setSingleLine(true);
}
}
}
Currently, you are querying your realtime database and ordering by its key name. To sort the RecyclerView list, you can try two approaches from here:
For approach one, you can try using your query like this:
Query query = reference.orderByChild("last_msg_time_stamp").limitToLast(10000);
Here, last_msg_time_stamp
might be the key inside Chats/$your_keys
which holds the last timestamp for that conversation. For approach two, I would say that in your adapter, you are taking this data and putting it. But before binding this data into list, you need to sort your list on the basis of your last message timestamp for all of the keys.
In my view, It would be beneficial to use approach one, since, it would be less processing-intensive way for the users. The realtime database would be pre-processing and the required list for you already.
The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.