Как Presentation слой в MVP передает данные
Комментарии (1)
Ответ сгенерирован нейросетью и может содержать ошибки
Передача данных из Presentation Layer в MVP
В архитектуре MVP (Model-View-Presenter), Presentation Layer (или Presenter) отвечает за бизнес-логику и управление View, выступая посредником между Model и View. Передача данных здесь двусторонняя: как от View к Presenter, так и от Presenter к View. Основные способы передачи данных из Presenter в View:
1. Интерфейсы View
View реализует интерфейс, который определяет методы для обновления UI. Presenter работает с этим интерфейсом, вызывая методы при изменении данных.
// Интерфейс View
interface UserProfileView {
fun showUserData(user: User)
fun showError(message: String)
fun showLoading()
fun hideLoading()
}
// Activity или Fragment реализует этот интерфейс
class UserProfileActivity : AppCompatActivity(), UserProfileView {
private lateinit var presenter: UserProfilePresenter
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_user_profile)
presenter = UserProfilePresenter(this)
presenter.loadUserData()
}
override fun showUserData(user: User) {
nameTextView.text = user.name
emailTextView.text = user.email
}
override fun showError(message: String) {
Toast.makeText(this, message, Toast.LENGTH_SHORT).show()
}
}
// Presenter вызывает методы View
class UserProfilePresenter(private val view: UserProfileView) {
fun loadUserData() {
view.showLoading()
// Предположим, что это асинхронный вызов
UserRepository.getUser { user ->
view.hideLoading()
if (user != null) {
view.showUserData(user)
} else {
view.showError("Failed to load user")
}
}
}
}
2. Колбэки и Listeners
Для обработки пользовательского ввода View передает в Presenter колбэки (например, через лямбды или интерфейсы).
// Presenter определяет интерфейс для событий
interface UserProfilePresenter {
fun onSaveButtonClicked(name: String, email: String)
fun onDeleteButtonClicked()
}
// Реализация Presenter
class UserProfilePresenterImpl(private val view: UserProfileView) : UserProfilePresenter {
override fun onSaveButtonClicked(name: String, email: String) {
if (name.isBlank()) {
view.showError("Name cannot be empty")
return
}
// Сохранение данных через Model
UserRepository.saveUser(User(name, email))
view.showSuccessMessage()
}
}
3. Наблюдатели (Observers)
Использование реактивных подходов (например, RxJava или Kotlin Flow) для передачи потоков данных.
class UserProfilePresenter(private val view: UserProfileView) {
private val disposable = CompositeDisposable()
fun observeUserData() {
UserRepository.getUserStream()
.subscribeOn(Schedulers.io())
.observeOn(AndroidSchedulers.mainThread())
.subscribe(
{ user -> view.showUserData(user) },
{ error -> view.showError(error.message ?: "Unknown error") }
).addTo(disposable)
}
fun dispose() {
disposable.dispose()
}
}
4. Модели состояния (State Models)
Presenter формирует модели состояния (например, UserState), которые содержат все данные для отображения, и передает их целиком во View.
data class UserState(
val isLoading: Boolean = false,
val user: User? = null,
val error: String? = null
)
class UserProfilePresenter(private val view: UserProfileView) {
private var currentState = UserState()
fun loadUserData() {
currentState = currentState.copy(isLoading = true)
view.render(currentState)
UserRepository.getUser { user ->
currentState = if (user != null) {
currentState.copy(isLoading = false, user = user, error = null)
} else {
currentState.copy(isLoading = false, error = "Load failed")
}
view.render(currentState)
}
}
}
Ключевые принципы:
- Разделение ответственности: Presenter не знает о деталях реализации View (только интерфейс), что упрощает тестирование.
- Пассивная View: View не должна содержать бизнес-логики, только отображать данные и передавать события.
- Управление жизненным циклом: Presenter должен учитывать жизненный цикл View (особенно на Android), чтобы избежать утечек памяти и crashes.
- Тестируемость: Presenter легко тестировать с помощью unit-тестов, используя mock-объекты View.
Пример полного цикла передачи:
- View → Presenter: Пользователь нажимает кнопку, View вызывает
presenter.onButtonClicked(). - Presenter → Model: Presenter запрашивает данные из Model (
UserRepository.getUser()). - Model → Presenter: Model возвращает данные (или ошибку) через колбэк.
- Presenter → View: Presenter вызывает метод интерфейса View (
view.showUserData(user)).
Этот подход обеспечивает чистую архитектуру, где Presentation Layer служит мостом между данными и их отображением, соблюдая принципы SOLID и тестируемости.