RecyclerView дублирует items,больше чем необходимо. В первый раз когда перехожу на экран все нормально, если выйти и вернуться происходит,дублирование
я пишу приложение чат на языке Java, используя FireBase и у меня возникла проблемма. Проблемма заключается в том, что когда я повторно после возврата в Activity_Main перехожу на экран контактов, контакты дублируются в RecyclerView, каждый раз это модет быть разное колличество. При чем передаваемые в адаптер данные верны.
К сожалению, я не смог самостоятельно найти и исправить причину.
Заранее благодарю Вас за помощь.
Заранее извиняюсь, если что-то не очень доходчиво изложил, я мнгновенно готов ответить на Ваши вопросы и уточнить.
На телефоне это выглядит так:
public class MainActivity extends AppCompatActivity {
private Toolbar toolbar;
private FloatingActionButton createChatBtn;
private FirebaseUser currentUser;
private FirebaseAuth mAuth;
private DatabaseReference rootRef;// ссылка для доступа к базе данных
private RecyclerView recyclerView;
private TextView batteryLevel;
private BroadCastBattery broadCastBattery;
private int READ_CONTACTS_PERMISSION = 1;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
mAuth = FirebaseAuth.getInstance();
currentUser = mAuth.getCurrentUser();
rootRef = FirebaseDatabase.getInstance().getReference();
createChatBtn = findViewById(R.id.fab_bt);
toolbar = findViewById(R.id.toolBar);
batteryLevel = findViewById(R.id.battery_level);
broadCastBattery = new BroadCastBattery();
setSupportActionBar(toolbar);
recyclerView = findViewById(R.id.incoming_message_recyclerview);
MainActivityAdapter mainActivityAdapter = new MainActivityAdapter(new ArrayList<>());
LinearLayoutManager linearLayoutManager = new LinearLayoutManager(this);
recyclerView.setHasFixedSize(true);
recyclerView.setLayoutManager(linearLayoutManager);
recyclerView.setAdapter(mainActivityAdapter);
onStart();
onResume();
onPause();
if (ContextCompat.checkSelfPermission(this, Manifest.permission.READ_CONTACTS) == PackageManager.PERMISSION_GRANTED) {
new Thread(() -> {
try {
readContacts();
} catch (Exception exception) {
runOnUiThread(() -> Toast.makeText(MainActivity.this, exception.toString(), Toast.LENGTH_SHORT).show());
}
}).start();
}else{
requestReadContactsPermission();
}
createChatBtn.setOnClickListener(v -> {
Intent contactIntent = new Intent(MainActivity.this, ContactsActivity.class);
startActivity(contactIntent);
});
REF_DATABASE_MESSAGES_ROOT.child(currentUser.getUid()).addValueEventListener(new ValueEventListener() {
@Override
public void onDataChange(@NonNull DataSnapshot snapshot) {
for (DataSnapshot child1 : snapshot.getChildren()) {
for (DataSnapshot child2 : child1.getChildren()) {
if (child2.getKey().equals("LastMessage")) {
getMessageFromDB(child1.getKey(), "LastMessage").addOnSuccessListener(message -> {
if (message.getSenderId().equals(currentUser.getUid())) {
getUserFromDB(message.getReceiverId()).addOnSuccessListener(user -> {
mainActivityAdapter.addIncomingMessage(new IncomingMessage(user.getUsername(), message.getText(), user.getImageURL(), user.getId()));
});
} else {
getUserFromDB(message.getSenderId()).addOnSuccessListener(user -> {
mainActivityAdapter.addIncomingMessage(new IncomingMessage(user.getUsername(), message.getText(), user.getImageURL(), user.getId()));
});
}
});
}
}
}
}
@Override
public void onCancelled(@NonNull DatabaseError error) {
}
});
}
protected void onStart() {
super.onStart();
if (currentUser == null) {
Intent welcomeIntent = new Intent(this, WelcomeActivity.class);
startActivity(welcomeIntent);
} else {
}
}
protected void onResume() {
super.onResume();
AppStates.updateState(AppStates.ONLINE, rootRef, currentUser);
registerReceiver(broadCastBattery, new IntentFilter(Intent.ACTION_BATTERY_CHANGED));
}
protected void onPause() {
super.onPause();
AppStates.updateState(AppStates.OFFLINE, rootRef, currentUser);
unregisterReceiver(broadCastBattery);
}
@Override
public boolean onCreateOptionsMenu(Menu menu) {
super.onCreateOptionsMenu(menu);
getMenuInflater().inflate(R.menu.options_menu, menu);
return true;
}
@Override
public boolean onOptionsItemSelected(@NonNull MenuItem item) {
super.onOptionsItemSelected(item);
if (item.getItemId() == R.id.menu_settings) {
Intent settingsIntent = new Intent(this, SettingsActivity.class);
startActivity(settingsIntent);
}
if (item.getItemId() == R.id.menu_logout) {
Dialog logout_dialog = new Dialog(this);
logout_dialog.setContentView(R.layout.logout_dialog);
logout_dialog.show();
Button yes_bt = logout_dialog.findViewById(R.id.yes_bt);
Button no_bt = logout_dialog.findViewById(R.id.no_bt);
yes_bt.setOnClickListener(v -> {
mAuth.signOut();
Intent loginIntent = new Intent(MainActivity.this, LoginActivity.class);
startActivity(loginIntent);
logout_dialog.cancel();
});
no_bt.setOnClickListener(v -> logout_dialog.cancel());
}
return true;
}
public void contactMatchCheck(List<Contact> contacts) {
rootRef.child("Phones").get().addOnSuccessListener(dataSnapshot -> {
for (DataSnapshot child : dataSnapshot.getChildren()) {
for (Contact contact : contacts) {
if (contact.getPhoneNumber().equals(child.getKey())) {
rootRef.child("Phone_contacts").child(currentUser.getUid()).child(child.getKey()).setValue(child.getValue().toString());
}
}
}
});
}
@SuppressLint("Range")
public void readContacts() {
ArrayList<Contact> contacts = new ArrayList<>();
getUserFromDB(currentUser.getUid()).addOnSuccessListener(user -> {
ContentResolver cr = getContentResolver();
Cursor cur = cr.query(ContactsContract.Contacts.CONTENT_URI, null,
null, null, null);
if (cur.getCount() > 0) {
while (cur.moveToNext()) {
String id = cur.getString(cur.getColumnIndex(ContactsContract.Contacts._ID));
String name = cur.getString(cur.getColumnIndex(ContactsContract.Contacts.DISPLAY_NAME));
Log.i("Names", name);
if (Integer.parseInt(cur.getString(cur.getColumnIndex(ContactsContract.Contacts.HAS_PHONE_NUMBER))) > 0) {
// Query phone here. Covered next
Cursor phones = getContentResolver().query(ContactsContract.CommonDataKinds.Phone.CONTENT_URI, null, ContactsContract.CommonDataKinds.Phone.CONTACT_ID + " = " + id, null, null);
while (phones.moveToNext()) {
String phone = phones.getString(phones.getColumnIndex(ContactsContract.CommonDataKinds.Phone.NUMBER)).replaceAll("[\\s,-]", "");
if (phone.charAt(0) == '0') {
Contact contact = new Contact(name, user.getCountryCode() + phone.replaceFirst("0", ""));
contacts.add(contact);
} else {
Contact contact = new Contact(name, phone);
contacts.add(contact);
}
}
phones.close();
}
}
}
cur.close();
contactMatchCheck(contacts);
});
}
private class BroadCastBattery extends BroadcastReceiver {
@Override
public void onReceive(Context context, Intent intent) {
int battery = intent.getIntExtra("level", 0);
batteryLevel.setText("Battery level: " + String.valueOf(battery) + "%");
REF_DATABASE_BATTERY.child(currentUser.getUid()).setValue(new Battery(currentUser.getUid(), String.valueOf(battery) + "%")).addOnCompleteListener(new OnCompleteListener<Void>() {
@Override
public void onComplete(@NonNull Task<Void> task) {
if (task.isSuccessful()) {
} else {
String exception = Objects.requireNonNull(task.getException()).toString();
Toast.makeText(MainActivity.this, "An error has occurred:" + exception, Toast.LENGTH_SHORT).show();
}
}
});
}
}
private void requestReadContactsPermission() {
//checks if we need to explain to user why this permission is needed for
if (ActivityCompat.shouldShowRequestPermissionRationale(this, Manifest.permission.READ_CONTACTS)) {
new AlertDialog.Builder(this).setTitle("Permission needed").setMessage("This permission is needed to read your phone contacts.").setPositiveButton("ok", (dialog, which) -> ActivityCompat.requestPermissions(MainActivity.this, new String[]{Manifest.permission.READ_CONTACTS}, READ_CONTACTS_PERMISSION)).setNegativeButton("cancel", (dialog, which) -> startActivity(new Intent(this,WelcomeActivity.class))).create().show();
} else {
ActivityCompat.requestPermissions(this, new String[]{Manifest.permission.READ_CONTACTS}, READ_CONTACTS_PERMISSION);
}
}
@Override
public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions, @NonNull int[] grantResults) {
super.onRequestPermissionsResult(requestCode, permissions, grantResults);
if (requestCode == READ_CONTACTS_PERMISSION) {
if (grantResults.length > 0 && grantResults[0] == PackageManager.PERMISSION_GRANTED) {
readContacts();
}
}
}
public Task<User> getUserFromDB(String uid) {
return REF_DATABASE_USERS_ROOT.child(uid).get().continueWith(task -> task.getResult().getValue(User.class));
}
public Task<Message> getMessageFromDB(String uid, String mid) {
return REF_DATABASE_MESSAGES_ROOT.child(currentUser.getUid()).child(uid).child(mid).get().continueWith(task -> task.getResult().getValue(Message.class));
}
}
Метод readContacts считывает все контакты с телефона. Метод contactMatchCheck проверяет, совпадают ли номера телефонов полученные в методе readContacts с номерами зарегистрированных пользователей в узле Phones и если да, то записывает их в узел с сurrentId в узле Phone_contacts.
Экран контактов
public class ContactsActivity extends AppCompatActivity {
private RecyclerView recyclerView;
private ImageButton backBt;
private Toolbar toolbar;
private FirebaseAuth mAuth;
private DatabaseReference rootRef;
private FirebaseUser currentUser;
private TextView batteryLevel;
private BroadCastBattery broadCastBattery;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_contacts);
backBt = findViewById(R.id.back_bt);
toolbar = findViewById(R.id.toolBar);
setSupportActionBar(toolbar);
mAuth = FirebaseAuth.getInstance();
currentUser = mAuth.getCurrentUser();
rootRef = FirebaseDatabase.getInstance().getReference();
batteryLevel = findViewById(R.id.battery_level);
broadCastBattery = new BroadCastBattery();
recyclerView = findViewById(R.id.recyclerView);
UserAdapter userAdapter = new UserAdapter(new ArrayList<>());
LinearLayoutManager linearLayoutManager = new LinearLayoutManager(this);
recyclerView.setHasFixedSize(true);
recyclerView.setLayoutManager(linearLayoutManager);
recyclerView.setAdapter(userAdapter);
onResume();
onPause();
onStop();
backBt.setOnClickListener(v -> {
Intent mainIntent = new Intent(ContactsActivity.this, MainActivity.class);
startActivity(mainIntent);
});
REF_DATABASE_USERS_ROOT.addValueEventListener(new ValueEventListener() {
@Override
public void onDataChange(@NonNull DataSnapshot snapshot) {
rootRef.child("Phone_contacts").child(currentUser.getUid()).get().addOnSuccessListener(dataSnapshot -> {
for (DataSnapshot phoneContact : dataSnapshot.getChildren()) {
getUserFromDB(phoneContact.getValue(String.class)).addOnSuccessListener(user -> userAdapter.addUser(user));
}
runOnUiThread(() -> toolbar.setSubtitle(userAdapter.getItemCount() + " contacts"));
});
}
@Override
public void onCancelled(@NonNull DatabaseError error) {
}
});
}
protected void onResume() {
super.onResume();
AppStates.updateState(AppStates.ONLINE, rootRef, currentUser);
registerReceiver(broadCastBattery, new IntentFilter(Intent.ACTION_BATTERY_CHANGED));
}
protected void onPause() {
super.onPause();
AppStates.updateState(AppStates.OFFLINE, rootRef, currentUser);
}
protected void onStop() {
super.onStop();
unregisterReceiver(broadCastBattery);
}
private class BroadCastBattery extends BroadcastReceiver {
@Override
public void onReceive(Context context, Intent intent) {
int battery = intent.getIntExtra("level", 0);
batteryLevel.setText("Battery level: " + String.valueOf(battery) + "%");
REF_DATABASE_BATTERY.child(currentUser.getUid()).setValue(new Battery(currentUser.getUid(), String.valueOf(battery) + "%")).addOnCompleteListener(new OnCompleteListener<Void>() {
@Override
public void onComplete(@NonNull Task<Void> task) {
if (task.isSuccessful()) {
} else {
String exception = Objects.requireNonNull(task.getException()).toString();
Toast.makeText(ContactsActivity.this, "An error has occurred:" + exception, Toast.LENGTH_SHORT).show();
}
}
});
}
}
public Task<User> getUserFromDB(String uid) {
return REF_DATABASE_USERS_ROOT.child(uid).get().continueWith(task -> task.getResult().getValue(User.class));
}
}
В классе ContactActivity в onCreate я повесил слушателя на узел Users, при изменении данных у пользователя,я обновляю контакты отображенные на экране, доставая их из узла Phone_contacts.
Адаптер:
public class UserAdapter extends RecyclerView.Adapter<UserAdapter.ViewHolder> {//отвечает за добавление данных в RecyclerView
private List<User> mUsers;
//constructor
public UserAdapter(List<User> mUsers) {
this.mUsers = mUsers;
}
public List<User> getMUsers() {
return mUsers;
}
@NonNull
@Override
public UserAdapter.ViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) {
View view = LayoutInflater.from(parent.getContext()).inflate(R.layout.user_item, parent, false);
return new ViewHolder(view);
}
@Override
//get and set data
public void onBindViewHolder(@NonNull UserAdapter.ViewHolder holder, int position) {
User user = mUsers.get(position);
holder.username.setText(user.getUsername());
if (user.getState().equals("online") || user.getState().equals("typing")) {
holder.state.setImageResource(R.color.green);
} else {
holder.state.setImageResource(R.color.transparent);
}
if (user.getImageURL() == null) {
holder.profile_image.setImageResource(R.drawable.profile);
} else {
Picasso.get().load(user.getImageURL()).into(holder.profile_image);
}
holder.currentUserId = user.getId();
}
@Override
public int getItemCount() {
return mUsers.size();
}
public void addUser(User user) {
mUsers.add(user);
notifyItemInserted(mUsers.size() - 1);
}
@Override
public long getItemId(int position) {
return position;
}
/* public void addAllUsers(ArrayList<User> users){
mUsers.addAll(users);
notifyAll();
}*/
@SuppressLint("NotifyDataSetChanged")
public void deleteAllUsers() {
mUsers.clear();
notifyDataSetChanged();
}
public void clear() {
int size = mUsers.size();
mUsers.clear();
notifyItemRangeRemoved(0, size);
}
static class ViewHolder extends RecyclerView.ViewHolder { //отвечает за элемент списка
public final TextView username;
public final ImageView profile_image;
public final CircleImageView state;
public String currentUserId;
public ViewHolder(View itemView) {
super(itemView);
//init views
profile_image = itemView.findViewById(R.id.profile_image);
username = itemView.findViewById(R.id.tvItemUsername);
state = itemView.findViewById(R.id.state);
//handle item click
itemView.setOnClickListener(v -> {
Intent singleChatIntent = new Intent(itemView.getContext(), SingleChatActivity.class);
singleChatIntent.putExtra("ContactID", currentUserId);
itemView.getContext().startActivity(singleChatIntent);
});
}
}
}







