Как мне создать метод для слушателей?

#android #kotlin #listener #viewmodel

Вопрос:

У моих слушателей изменений есть время жизни, и чтобы не хранить их в памяти, я думаю, что мне нужно добавить метод, например, removeItemChangeListener и вызвать его, например, в onClear методе модели представления. Насколько я знаю, onClear метод переопределен в onCreate отношении действия. Кроме того, мне кажется, что мне нужно преобразовать тип прослушивателя в интерфейс.

myitemsрепозиционный.кт

 interface MyItemsRepository {
    val items: List<ItemModel>

    fun setFavorite(itemModel: ItemModel, isFavorite: Boolean)

    fun addItemChangeListener(listener: () -> Unit)
}
 

ContentViewModel.kt

 class ContentViewModel(
    private val repository: MyItemsRepository
) : ViewModel() {

    private val _items: MutableLiveData<List<ItemModel>> = MutableLiveData()
    val items: LiveData<List<ItemModel>>
        get() = _items

    var isFavorite: Boolean = false

    init {
        repository.addItemChangeListener {
            getItems()
        }
    }

    fun changeFavoriteState(item: ItemModel, favorite: Boolean) {
        repository.setFavorite(item, favorite)
    }

    fun getItems() {
        _items.value = if (isFavorite) {
            repository.items.filter { it.isFavorite }
        } else {
            repository.items
        }
    }

    class Factory : ViewModelProvider.Factory {
        override fun <T : ViewModel?> create(modelClass: Class<T>): T {
            return ContentViewModel(MyItemsRepositoryImpl.getInstance()) as T
        }
    }
}
 

Мне нужна ваша помощь в написании кода. Я мысленно понимаю, как это сделать, но я не знаю, как это написать. Я был бы очень признателен за письменный пример с объяснением.

Комментарии:

1. Меня смущает ваша реализация, почему вы используете interface amp; listeners. Разве вы не можете просто добиться всего, чего хотите, создав класс репозитория, рассматривая его как локальный источник данных и работая с ним? Если вы следуете какому-либо учебнику, возможно, упомяните его ссылку в посте. Похоже, вы усложняете такую небольшую архитектуру.

2. И, может быть, объясните свой вариант использования, чего вы здесь пытаетесь достичь?

3. @ParagPawar Я отвечаю на ваш вопрос о локальном источнике данных. Дело в том, что мне было дано задание создать то, что вы видите в моем коде, и я только сейчас работаю над исправлением любых комментариев. Я понимаю, что мое руководство все устроило, и поэтому мне нужно только сделать то, о чем я писал выше. Не стоит переписывать тип слушателя, наверное, это всего лишь мои догадки.

Ответ №1:

Может быть , попробуйте вызвать метод removeItemChangeListener так же, как вы вызываете setFavorite , просто вызовите его из onCleared метода ViewModel

 class ContentViewModel(
    private val repository: MyItemsRepository
) : ViewModel() {

    ...

    override fun onCleared() {
        super.onCleared()
        repository.removeItemChangeListener()
    }

}
 

И в вашем хранилище это будет что-то вроде этого:

 override fun removeItemChangeListener() {
    listeners.clear()
}
 

Вы действительно не можете сделать что-то подобное: listeners.remove(listener) потому что как вы все равно собираетесь передавать прослушиватель из ViewModel в репозиторий?

Добавьте removeItemChangeListener метод в интерфейс MyItemsRepository

 interface MyItemsRepository {
    
    ...

    fun removeItemChangeListener()
}
 

Опять же, я еще не проверял это на самом деле, но это должно сработать.

Редактировать:

Разный подход:

 class ContentViewModel(
    private val repository: MyItemsRepository
) : ViewModel() {

    var listener = {
        getItems()
    }

    init{
        repository.addItemChangeListener {
            listener
        }
    }

    ...

    override fun onCleared() {
        super.onCleared()
        repository.removeItemChangeListener(listener)
    }

}
 

И в вашем хранилище это будет что-то вроде этого:

 override fun removeItemChangeListener(listener: () -> Unit) {
    listeners.remove(listener)
}
 

Добавьте removeItemChangeListener метод в интерфейс MyItemsRepository

 interface MyItemsRepository {
    
    ...

    fun removeItemChangeListener(listener: () -> Unit)
}
 

Я не совсем уверен, сработает ли это. Попробуйте и дайте мне знать.

Комментарии:

1. При попытке вызвать функцию removeItemChangeListener () в модели представления появляется ошибка «Неразрешенная ссылка: removeItemChangeListener».

2. Проверьте правильность метода removeItemChangeListener() , возможно, проверьте орфографию, синтаксис. Или просто скопируйте и вставьте код, который я написал

3. Нет, это не сработает, понял проблему. Я отредактирую ответ.

4. Студия Android предлагает: Создать абстрактную функцию «MyItemsRepository.removeItemChangeListener»

5. Отредактировал ответ, пожалуйста, попробуйте прямо сейчас

Ответ №2:

Это выглядело бы точно так же, как ваша addItemChangeListener функция, за исключением того, что она должна вызывать remove вместо add . Не уверен, в какой части концепции вы не уверены. Определение его как интерфейса необязательно. Интерфейс, возможно, поможет лучше донести цель слушателя, но не изменит функциональность. Если вы это сделаете, вы, вероятно, захотите определить его как a fun interface , потому что интерфейсы более увлекательны, если вы можете использовать лямбды для их представления.

Все это говорит о том, что если вы открыты для сопрограмм, вашему репо будет легче раскрыть поток. Затем, если ViewModel подпишется на поток, он автоматически откажется от подписки, когда выйдет за рамки.