Добавление уникальных элементов в recyclerView из geoQuery - PullRequest
1 голос
/ 09 мая 2020

Я создал приложение, которое показывает элементы пользователей рядом со мной.

Я нахожу людей, которые находятся рядом со мной, используя geoQuery, и если они рядом со мной, я ищу в базе данных, какие предметы у них есть Я заполняю ими RecyclerView.

Я делаю это, используя:

List<DiscoverItems> items = new ArrayList<>();

GeoQuery geoQuery = geoFire.queryAtLocation(new GeoLocation(Lat, Lon), Radius);
geoQuery.addGeoQueryEventListener(new GeoQueryEventListener() {
    @Override
    public void onKeyEntered(String key, GeoLocation location) {

        String UserID = key;

        if (!UserID.equals(auth.getUid())) {
            db.collection("Users").document(UserID).collection("MyItems").get().addOnCompleteListener(task_count -> {
                if (task_count.isSuccessful()) {
                    for (DocumentSnapshot document_near : task_count.getResult()) {
                        items.add(new DiscoverItems(document_near.getString("ItemID")));
                    }

                }
            });
        }

        discoverItemAdapter = new DiscoverItemAdapter(items, listener);
        rv_NearMeItems.setAdapter(discoverItemAdapter);

    }

    @Override
    public void onKeyExited(String key) {

    }

    @Override
    public void onKeyMoved(String key, GeoLocation location) {

    }

    @Override
    public void onGeoQueryReady() {

    }

    @Override
    public void onGeoQueryError(DatabaseError error) {

    }
});

Однако моя проблема в том, что у некоторых пользователей есть один и тот же элемент, потому что тогда он появится дважды в the recyclerView, в то время как мне хотелось, чтобы у него были уникальные элементы. следующее:

List<DiscoverItems> items= new ArrayList<>();
Set<DiscoverItems> itemkset = new HashSet<>();

GeoQuery geoQuery = geoFire.queryAtLocation(new GeoLocation(Lat, Lon), Radius);
geoQuery.addGeoQueryEventListener( new GeoQueryEventListener() {
    @Override
    public void onKeyEntered(String key, GeoLocation location) {

        String UserID = key;

        if (!UserID.equals( auth.getUid() )) {
            db.collection( "Users" ).document( UserID ).collection( "MyItems" ).get().addOnCompleteListener( task_count -> {
                if (task_count.isSuccessful()) {
                    for (DocumentSnapshot document_near : task_count.getResult()) {
                        itemset.add( new DiscoverItems( document_near.getString( "ItemID" ) ) );
                    }
                }
            } );
        }
        List<DiscoverItems> itemsWithoutDuplicates = new ArrayList<>(new HashSet<>(itemset));
        for (DiscoverItems item: itemsWithoutDuplicates){
            items.add(item);
        }
    discoverItemAdapter = new DiscoverItemAdapter(items, listener);
    rv_NearMeItems.setAdapter(discoverItemAdapter);
    }

Но это не работает, так как, например, если у меня 2 пользователя, onKeyEntered будет вызываться дважды. Для первого пользователя он добавит к itemset, скажем, 4 элемента, которые не идентичны, и все будет в порядке. Затем он вызовет второго пользователя, который добавит еще 3 элемента в набор, которые не идентичны, и все будет в порядке.

Я что-то упустил? Потому что с приведенным выше кодом я получаю несколько элементов.

Спасибо

1 Ответ

1 голос
/ 09 мая 2020

Я не знаю сложности ваших объектов, но вы можете попробовать изменить List<> int на Set<>. В общем, Set - это коллекция, которая не содержит повторяющихся элементов (например, на основе их хэш-кода).

1) Сравниваемые объекты

Прежде всего вам нужно переопределить equals() и hashCode() в классе DiscoverItems для работы с коллекциями на основе ha sh (например, HashSet).

Вы можете сгенерировать эти методы в Android Studio и выбрать основу на основе каких полей вы можете сказать, что «эти два объекта одинаковы». Иногда нет необходимости сравнивать все поля (вы можете использовать, например, только имя или какой-либо идентификатор).

В вашем случае, вам нужно сравнить это поле, которое вы передаете конструктору класса DiscoverItems . Это может выглядеть так:

@Override
public boolean equals(Object object) {
    if (this == object) return true;
    if (object == null || getClass() != object.getClass()) return false;
    DiscoverItems that = (DiscoverItems) object;
    return Objects.equals(itemID, that.itemID);
}

@Override
public int hashCode() {
    return Objects.hash(itemID);
}

2) Коллекция

Итак, измените:

List<DiscoverItems> items = new ArrayList<>();

на:

Set<DiscoverItems> items = new HashSet<>();

Когда вам нужна проверка в одном месте, вы можете преобразовать:

List ---> Set ---> List

например:

Set<DiscoverItems> set = new HashSet<>(items);

if (items.size() == set.size()) {
    // No duplicates, use original list
} else {
    // Duplicates removed, use new list
    List<DiscoverItems> itemsWithoutDuplicates = new ArrayList<>(set);
}

или без дополнительных условий:

Set<DiscoverItems> set = new HashSet<>(items);
List<DiscoverItems> itemsWithoutDuplicates = new ArrayList<>(set);

или как одно- лайнер:

List<DiscoverItems> itemsWithoutDuplicates = new ArrayList<>(new HashSet<>(items));

Подсказка

Вы должны назвать свой класс DiscoverItem, а не DiscoverItems. Потому что он представляет ОДИН предмет, а не много.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...