I am getting ConcurrentModificationException while creating a chat application - android

While displaying the recent chats fragment in the application I am fetching my chats from firebase and filtering out the chats by their receiverID and senderID in the chat object to display the recent chats.
The problem says ConcurrentModificationException in ArrayList and it looks like due to the complexity of searching id in the array it occurred, I need a solution to minimize this chat filteration complexity.
// private List<String> stringList; Declaration at top
stringList = new ArrayList<>();
firebaseUser = FirebaseAuth.getInstance().getCurrentUser();
databaseReference = FirebaseDatabase.getInstance().getReference("BaatCheet/Chats/");
databaseReference.addValueEventListener(new ValueEventListener() {
#Override
public void onDataChange(#NonNull DataSnapshot dataSnapshot) {
//userModelList.clear();
for (DataSnapshot dataSnapshot1 : dataSnapshot.getChildren()) {
MessageModel messageModel = dataSnapshot1.getValue(MessageModel.class);
if (messageModel.getSender().equals(firebaseUser.getUid())){
stringList.add(messageModel.getReceiver());
}
if (messageModel.getReceiver().equals(firebaseUser.getUid())){
stringList.add(messageModel.getSender());
}
}
readChat();
}
#Override
public void onCancelled(#NonNull DatabaseError databaseError) {
}
});
The read chat function
private void readChat() {
userModelList = new ArrayList<>();
databaseReference = FirebaseDatabase.getInstance().getReference("BaatCheet/Users/");
databaseReference.addValueEventListener(new ValueEventListener() {
#Override
public void onDataChange(#NonNull DataSnapshot dataSnapshot) {
userModelList.clear();
for (DataSnapshot dataSnapshot1 : dataSnapshot.getChildren()){
UserModel userModel = dataSnapshot1.getValue(UserModel.class);
for (String id: stringList){
if (userModel.getId().equals(id)){
if (userModelList.size() !=0){
for (UserModel userModel1 : userModelList){
if (!userModel.getId().equals(userModel1.getId())){
userModelList.add(userModel);
Log.d("DataAdded",userModel.getId());
} // If the existing list don't have same value for sender and reciever
} // end of inner userModel
} else {
userModelList.add(userModel);
Log.d("DataAdded",userModel.getId());
} // end of else
} // end of userModel id equals string id
} // end of String is loop
} // end of DataSnapshot loop
usersAdapter = new UsersAdapter(userModelList);
recyclerView.setAdapter(usersAdapter);
} // end of onDataChange
#Override
public void onCancelled(#NonNull DatabaseError databaseError) {
}
});
}// end of readChat()
The results would be the recyclerView of recent chats containing the chats which contain messages either send by the sender or receiver to each other.

In the following snippet of code :
for (UserModel userModel1 : userModelList){
if (!userModel.getId().equals(userModel1.getId())){
userModelList.add(userModel);
Log.d("DataAdded",userModel.getId());
} // If the existing list don't have same value for sender and reciever
} //
You are modifying userModelList while iterating through userModelList. This is not allowed and is the cause of ConcurrentModificationException.
There are few ways to simplify the logic, the simplest (albeit not the best) would be to convert this foreach loop into a simple for i loop.
for (int i = 0; i< userModelList.size(); i++) {
UserModel userModel1 = userModelList.get(i);
if (!userModel.getId().equals(userModel1.getId())){
userModelList.add(userModel);
Log.d("DataAdded",userModel.getId());
} // If the existing list don't have same value for sender and reciever
} //

Basically to handle this complexity I am now using separate nodes just for storing the chatLists as such now I don't need to read chats for filtering the recent chats.
The below code is for creating a new node everytime user sends a message it will update the node if the recieverID is different.
dbrefChatList = FirebaseDatabase.getInstance().
getReference("BaatCheet/ChatList/")
.child(senderuserID)
.child(receiveruserID);
dbrefChatList.addListenerForSingleValueEvent(new ValueEventListener() {
#Override
public void onDataChange(#NonNull DataSnapshot dataSnapshot) {
if (!dataSnapshot.exists()){
dbrefChatList.child("id").setValue(receiveruserID);
}
}
#Override
public void onCancelled(#NonNull DatabaseError databaseError) {
}
});
As such ChatList is a Model Class which contains single String called "id" and this id will be used to search in the node.
The below code is for the ChatFragment which fetches the chatList from firebase and set the data to recycler view.
// private List<ChatList> chatList; Declaration at top
chatListList = new ArrayList<>();
firebaseUser = FirebaseAuth.getInstance().getCurrentUser();
databaseReference = FirebaseDatabase
.getInstance()
.getReference("BaatCheet/ChatList")
.child(firebaseUser.getUid());
databaseReference.addValueEventListener(new ValueEventListener() {
#Override
public void onDataChange(#NonNull DataSnapshot dataSnapshot) {
chatListList.clear();
for (DataSnapshot snapshot : dataSnapshot.getChildren()){
ChatList chatList = snapshot.getValue(ChatList.class);
chatListList.add(chatList);
}
myChatList();
}
#Override
public void onCancelled(#NonNull DatabaseError databaseError) {
}
});
The function myChatList act as the function of readChat in the problem statement.
private void myChatList() {
userModelList = new ArrayList<>();
databaseReference = FirebaseDatabase.getInstance().getReference("BaatCheet/Users/");
databaseReference.addValueEventListener(new ValueEventListener() {
#Override
public void onDataChange(#NonNull DataSnapshot dataSnapshot) {
userModelList.clear();
for (DataSnapshot snapshot : dataSnapshot.getChildren()){
UserModel userModel = snapshot.getValue(UserModel.class);
for (ChatList chatList : chatListList){
if (userModel.getId().equals(chatList.getId())){
userModelList.add(userModel);
}
}
}
usersAdapter = new UsersAdapter(userModelList);
recyclerView.setAdapter(usersAdapter);
}
#Override
public void onCancelled(#NonNull DatabaseError databaseError) {
}
});
}

You can set a flag while traversing the array, after it's done, add it if it doesn't exist yet:
// Display 1 user from chats
for (String id : str_usersList) {
if (user.getId().equals(id)) {
if (userList.size() != 0) {
boolean exists = false;
// If not exists then add
for (User user1 : userList) {
if (user.getId().equals(user1.getId())) {
exists = true;
}
}
if (!exists) {
userList.add(user);
}
} else {
userList.add(user);
}
}
}

Related

Android Firebase push and get Array List

I have a questions how could i push array list to my freebase data base
and also read it to add a new element , then push it again.
In the above photo you can see i have added array list joinedStudents
and i need to read it and push new elements to it
I've tried the following
DatabaseReference requestsRef = FirebaseDatabase.getInstance().getReference();
requestsRef.child("requests").child(requestID).child("joinedStudents");
requestsRef.addValueEventListener(new ValueEventListener() {
#Override
public void onDataChange(#NonNull DataSnapshot dataSnapshot) {
for (DataSnapshot d : dataSnapshot.getChildren()) {
String jR = d.getValue(String.class);
joinedStudents.add(jR);
}
joinedStudents.add(studentID);
}
#Override
public void onCancelled(#NonNull DatabaseError databaseError) {
Log.d(TAG, "error fetching data from firebase");
}
});
for (String string : joinedStudents) {
requestsRef.child("requests").child(requestID).child("joinedStudents").setValue(string);
}
but it's not working
I believe you have your references slightly mixed up. Try something like:
DatabaseReference joinedStudentsRef = FirebaseDatabase.getInstance().getReference().child("requests").child(requestID).child("joinedStudents");
joinedStudentsRef.addValueEventListener(new ValueEventListener() {
#Override
public void onDataChange(#NonNull DataSnapshot dataSnapshot) {
for (DataSnapshot d : dataSnapshot.getChildren()) {
String jR = d.getValue(String.class);
joinedStudents.add(jR);
}
joinedStudents.add(studentID);
}
#Override
public void onCancelled(#NonNull DatabaseError databaseError) {
Log.d(TAG, "error fetching data from firebase");
}
});
for (String string : joinedStudents) {
joinedStudentsRef.child("1").setValue(string); // setValue is for key, value
// but you have an array
}
Where your reference is now the direct node that you want to monitor/read/write

Firebase Database reference in android

My current code is this:
String key = FirebaseDatabase.getInstance().getReference().child("posts").child("???").child("numLikes").toString;
How to get numLikes value?
final ArrayList<Integer> arrayList = new ArrayList<>();
DatabaseReference dbRef = FirebaseDatabase.getInstance().getReference("posts");
dbRef.addListenerForSingleValueEvent(new ValueEventListener() {
#Override
public void onDataChange(#NonNull DataSnapshot dataSnapshot) {
arrayList.clear();
for (DataSnapshot ds: dataSnapshot.getChildren()) {
int numLike = ds.child("numLikes").getValue(Integer.class);
arrayList.add(numLike);
}
}
#Override
public void onCancelled(#NonNull DatabaseError databaseError) {
}
});
Try this code, here you don't know pushkey so I have used forEach loop to jump one level down. The arraylist used here will contain all numLikes for your users.

Retrieve first child from a parent in Firebase

I am working on an Android application. I want the first child (first UID) of the parent 'support' and store it in a String variable. How do I get the value of the first UID from the list?
I tried one approach. It doesn't work though.
#Override
public void onDataChange(DataSnapshot dataSnapshot1) {
if (dataSnapshot1.exists()) {
String futureUID = "";
for(DataSnapshot futureUIDdatasnapshot:dataSnapshot1.getChildren() ){
futureUID = futureUIDdatasnapshot.getKey();
break;
}
/*Getting the first UID from the list of UID's in queue in 'future'*/
futureUID = dataSnapshot1.getChildren().iterator().next().getKey();
/*Moving a card from 'future' to 'serving'*/
societyServiceUIDReference.child(FIREBASE_CHILD_SERVING).child(futureUID).setValue(FIREBASE_ACCEPTED);
/*Removing the UID from 'future' after it is placed in 'serving'*/
societyServiceUIDReference.child(FIREBASE_CHILD_FUTURE).child(futureUID).removeValue();
}
}
#Override
public void onCancelled(DatabaseError databaseError) {
}
NOTE: 'futureUID' is the UID I want
Try the following:
DatabaseReference ref=FirebaseDatabase.getInstance().getReference().child("support");
Query queryUid=ref.orderByKey().limitToFirst(1);
queryUid.addListenerForSingleValueEvent(new ValueEventListener() {
#Override
public void onDataChange(DataSnapshot dataSnapshot) {
for (DataSnapshot datas : dataSnapshot.getChildren()) {
String key=datas.getKey();
}
}
#Override
public void onCancelled(DatabaseError databaseError) {
}
});
Try
DatabaseReference mDatabase;
mDatabase = FirebaseDatabase.getInstance().getReference();
.orderByKey().limitToFirst(n) is what does the trick. It orders the query results by key and returns only the first n results; in this case 1
mDatabase.getChild("support").orderByKey().limitToFirst(1)
.addListenerForSingleValueEvent(new ValueEventListener () {
#Override
public void onDataChange(DataSnapshot dataSnapshot) {
if(dataSnapshot.exists()){
for (DataSnapshot supportItem: dataSnapshot.getChildren()) {
String futureUID =supportItem.getKey();
}
}
}
}
#Override
public void onCancelled(DatabaseError databaseError) {
//Catch your error here
}
});
see Work with Lists of Data on Android

Displaying the database nodes from Firebase in a list in Android

A simple question:
Referring to my database image, I want to get the values of the children of node "user" in a list in an Activity, i.e. values "a" and "m" should be displayed in the list.
What should I use and how?
Please try this code:
DatabaseReference yourRef = FirebaseDatabase.getInstance().getReference().child("user");
yourRef.addValueEventListener(new ValueEventListener() {
#Override
public void onDataChange(DataSnapshot dataSnapshot) {
List<String> usersList = new ArrayList<>();
for (DataSnapshot ds : dataSnapshot.getChildren()) {
String userName = (String) ds.getKey();
usersList.add(userName);
}
}
#Override
public void onCancelled(DatabaseError databaseError) {
throw databaseError.toException(); // don't ignore errors
}
});
This is the way in which you'll have in your list, a, m ans so on.
Hope it helps.
You can get the info from the docs here
List<User> allUsers = new ArrayList<>();
DatabaseReference ref = FirebaseDatabase.getInstance().getReference().child("user");
ref.addValueEventListener(new ValueEventListener() {
#Override
public void onDataChange(DataSnapshot dataSnapshot) {
allUsers.clear();
for (DataSnapshot userSnapshot: dataSnapshot.getChildren()) {
allUsers.add(userSnapshot.getValue(User.class));
}
yourRecyclerViewAdapter.notifyDataSetChanged();
}
#Override
public void onCancelled(DatabaseError databaseError) {
// Getting Users failed, log a message
Log.w(TAG, "loadUser:onCancelled", databaseError.toException());
// ...
}
});

Get last node in Firebase database Android

I want to get item in the last node added in firebase database from my Android. You can see on the image below i'm not sure how to get the specific node, because unique key is created by Firebase. How to reference to auto-created node and child inside? Thanks a lot
The last node
Try this:
DatabaseReference databaseReference = FirebaseDatabase.getInstance().getReference();
Query lastQuery = databaseReference.child("mp").orderByKey().limitToLast(1);
lastQuery.addListenerForSingleValueEvent(new ValueEventListener() {
#Override
public void onDataChange(DataSnapshot dataSnapshot) {
String message = dataSnapshot.child("message").getValue().toString();
}
#Override
public void onCancelled(DatabaseError databaseError) {
// Handle possible errors.
}
});
Hope this helps!
This might work:
DatabaseReference db = FirebaseDatabase.getInstance().getReference().child("mp");
Query query = db.orderByKey().limitToLast(1);
query.addListenerForSingleValueEvent(new ValueEventListener() {
#Override
public void onDataChange(DataSnapshot dataSnapshot) {
for (DataSnapshot child: dataSnapshot.getChildren()) {
Log.d("User key", child.getKey());
Log.d("User val", child.child("message").getValue().toString());
}
}
#Override
public void onCancelled(DatabaseError databaseError) {
// TODO: Handle errors.
}
});
I prefer to write and retrieve data through objects.
MyObject is POJO.
#Override
public void onDataChange(DataSnapshot dataSnapshot) {
for (DataSnapshot data : dataSnapshot.getChildren()) {
MyObject myObject = data.getValue(MyObject.class);
Log.i(TAG, data.getKey() + " = " + myObject.toString());
}
}
console.log('last messages', messages[messages.length-1]);

Categories

Resources