June 22, 2024

Освой Паттерн Observable: Управляй Состоянием и Ас…

Паттерн Observable, известный как “наблюдатель”, используется для построения отношений “один ко многим” между объектами. Один объект (наблюдаемый) сообщает нескольким другим объектам (наблюдателям) о произошедших изменениях. Это полезно в Android для управления состоянием UI и асинхронными операциями.

Составляющие:

Observable (наблюдаемый): Объект, который генерирует события.
Observer (наблюдатель): Объект, который подписывается на события и получает уведомления об изменениях.
Subscription (подписка): Механизм, позволяющий наблюдателю подписаться на наблюдаемый объект и получать уведомления.

Вот основа паттерна Observable. Но чтобы это запомнилось лучше, давайте рассмотрим пару аналогий.

Аналогии для понимания

- Подписка на газету: Представьте, что Observable — это газета, а Observer — подписчик. Газета выпускает новые номера (события), и подписчик получает их (уведомления). Если подписчик хочет перестать получать газету, он может отменить подписку (отписаться).

- Уведомления в социальных сетях: В социальных сетях, когда кто-то публикует новый пост (Observable), его подписчики (Observers) получают уведомления. Если подписчик больше не хочет получать уведомления, он может отписаться от этого пользователя.

Теперь, когда мы разобрались с базовыми понятиями, давайте перейдем к практическому использованию паттерна Observable в Android.

Основные концепции Observable в Android

В Android паттерн Observable часто используется для управления состоянием пользовательского интерфейса с помощью StateFlow и ViewModel. Теперь давайте рассмотрим, как это реализуется на практике.

// ViewModel
class MyViewModel : ViewModel() {
 
  private val _data = MutableStateFlow("Initial value")
  val data: StateFlow<String> get() = _data

  fun updateData(newData: String) {
     _data.value = newData
   }
}

// Activity
class MyActivity : AppCompatActivity() {

  private lateinit var viewModel: MyViewModel

  override fun onCreate(savedInstanceState: Bundle?) {
   super.onCreate(savedInstanceState)
   setContentView(R.layout.activity_main)
   viewModel = ViewModelProvider(this).get(MyViewModel::class.java)
   lifecycleScope.launchWhenStarted {
     viewModel.data.collect { updatedData ->
       findViewById<TextView>(R.id.textView).text = updatedData
     }
   }
   viewModel.updateData("Новое значение")
 }
}

ViewModel:
— Хранит данные и логику обновления.
— Использует `MutableStateFlow` для хранения наблюдаемых данных.
— Метод `updateData` обновляет значение в StateFlow.

Activity:
— Создает экземпляр ViewModel и подписывается на изменения StateFlow.
— Использует lifecycleScope и collect для обновления UI при изменении данных.

Вот мы создали реальный пример использования паттерна Observable с StateFlow. Теперь давайте рассмотрим более сложный пример.

Более сложный пример: наблюдение за изменениями списка

Допустим, у нас есть список задач, и мы хотим обновлять UI при добавлении, удалении или изменении задач.

// ViewModel
class TasksViewModel : ViewModel() {
    private val _tasks = MutableStateFlow<List<Task>>(emptyList())
    val tasks: StateFlow<List<Task>> get() = _tasks

    fun addTask(task: Task) {
        _tasks.value = _tasks.value + task
    }

    fun removeTask(task: Task) {
        _tasks.value = _tasks.value - task
    }

    fun updateTask(updatedTask: Task) {
        _tasks.value = _tasks.value.map { task ->
            if (task.id == updatedTask.id) updatedTask else task
        }
    }
}

// Activity
class TasksActivity : AppCompatActivity() {

    private lateinit var viewModel: TasksViewModel

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_tasks)

        viewModel = ViewModelProvider(this).get(TasksViewModel::class.java)

        val tasksAdapter = TasksAdapter()

        findViewById<RecyclerView>(R.id.recyclerView).apply {
            adapter = tasksAdapter
            layoutManager = LinearLayoutManager(this@TasksActivity)
        }

        lifecycleScope.launchWhenStarted {
            viewModel.tasks.collect { tasks ->
                tasksAdapter.submitList(tasks)
            }
        }
    }
}

ViewModel:
— Хранит список задач в MutableStateFlow.
— Методы addTask, removeTask, updateTask обновляют список задач.

Activity:
— Создает экземпляр ViewModel и подписывается на изменения списка задач.
— Обновляет RecyclerView с помощью адаптера при изменении списка задач.

Этот пример показывает, как можно использовать StateFlow для наблюдения за изменениями списка задач и обновления UI.

Ну чтож, теперь вы знаете чуть больше!