Передать/хранить тип Enum

171
16 декабря 2021, 16:00

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

Есть приложение, в котором много перечисляемых значений, по типу:

Gender:
MALE(R.string.female),
FAMALE(R.string.male)
HowMany:
EVERY_DAY(R.string.every_day),
ONCE_WEEK(R.string.once_week),
THREE_A_WEEK(R.string.three_a_week),
ONCE_MONTH(R.string.once_month),
ONCE_YEAR(R.string.once_year),
ETC(R.string.etc)

И так далее, они разных типов, некоторые возможно в будущем будут содержать не только строки. Они будут приходить из сервака, и храниться в БД.

По дизайну есть достаточно специфичная вьюшка, на подобие spinner, который пришлось кастомизировать из нескольких инных вьюх. Так же использую DataBinding и при помощи биндинга передаю enum во вьюшку, но хотелось бы как-то унифицировать вьюшку, так как таких вьюшек будет также много как и перечисляемых значений.

Вопрос: Как использовать в этой вьюшке унификацию принимаемых значений?

Сейчас список наполняю так:

for (item in Gender.values()) {
  popupMenu.menu.add(item.resId!!)
}

Вместо Gender нужна переменная, которая принимала бы любые Enum.

Answer 1

(Ответ дан с использованием java)

нужна переменная, которая принимала бы любые Enum

Ответ:

Для того, чтобы передать параметром метода любой Enum следует использовать обобщение. Припустим, у нас есть метод, принимающий любой подтип Enum и перебирает его константные значения:

public <E extends Enum<E>> void foo(E e){
       for(Enum<E> item : e.getClass().getEnumConstants()){
            // do something
       }
    }

Заметьте, что в этом примере не используется метод values(). Все потому, что он не есть методом Enum. Компилятор автоматически добавляет этот метод для всех подкласов enum. Следовательно, если мы используем как параметр дженерик, то этого не будет достаточно для того, чтобы вызвать values().

Но

Конкретно в вашем примере это не получится. В цикле вы вызываете специфичное для Gender поле resId. Любой Enum не подойдет.

Решение:

Для начала нужно создать интерфейс, который будут реализовывать все Enum, что содержат ID ресурса. Пример:

public interface ResourceContainer {
    int getResourceId();
}

Теперь, нужно имплементировать наш интерфейс во всех enum-классах, содержащих ресурс:

public enum Gender implements ResourceContainer {
    MALE(R.string.male){
        @Override
        public int getResourceId() {
            return this.idResource;
        }
    },
    FEMALE(R.string.female){
        @Override
        public int getResourceId() {
            return this.idResource;
        }
    };
    protected int idResource;
    Gender(int idResource) {
        this.idResource = idResource;
    }
}

Теперь модифицируем метод описаный выше под нашы нужды. Доставать Id ресурса будем через наш новый метод getResourceID():

      public static <E extends Enum<E> & ResourceContainer> void updatePopupMenu(Class<E> resourceContainer,
                                                                               PopupMenu popupMenu){
        for (ResourceContainer enumValue : resourceContainer.getEnumConstants()) {
            popup.getMenu().add(enumValue.getResourceId());
        }
    }

Так, как мы не можем инициализировать enum, параметром метода следует передать класс. Вызов метода будет выглядеть так:

  updatePopupMenu(Gender.class, popupMenu);

Как-то так.

READ ALSO
Java Method(Overloading)

Java Method(Overloading)

Ребята перегрузка методов выполняетсь во время компиляции(Compile-Time) или во время выполнения (Run-Time) ?

206
Java. Canvas. JFrame

Java. Canvas. JFrame

Код ниже рисует линию, каждую секунду новуюКак можно сделать, чтобы новая линия добавлялась к старой? То есть хочу видеть через условно двадцать...

130
MediaType utf-8

MediaType utf-8

Отправляю запрос на сервер

194
Помогите со связным списком на Java

Помогите со связным списком на Java

Нужно удалить повторяющиеся элементы связного списка спискаВывести сначала исходный связный список, затем уже с удалением

106