Как избежать дублирования состояния между родительским и дочерним экранами при передаче параметров, созданных дочерними Android

Форум для тех, кто программирует под Android
Ответить
Anonymous
 Как избежать дублирования состояния между родительским и дочерним экранами при передаче параметров, созданных дочерними

Сообщение Anonymous »

В Jetpack Compose с MVVM у меня есть родительский экран, содержащий 3 дочерних экрана. Навигация используется для перемещения между дочерними экранами.
Каждый дочерний экран может создавать PDF-файл разными способами:
  • Один загружает его из Интернета.
  • Другой создает его локально.
  • Другой может создавать его на основе данных базы данных.
Независимо от того, как они генерируются, все три дочерних экрана должны быть умеет:
  • Отобразить PDF-файл.
  • Отправить его по электронной почте.
  • Распечатать.
Проблема в том, что эти три действия дублируют код на всех дочерних экранах. Чтобы избежать дублирования, я подумал о переносе логики отображения, отправки и печати PDF-файла на родительский экран. Единственный способ, которым я могу это сделать, это:
  • Каждый дочерний экран сохраняет сгенерированный PDF-файл в своем собственном uiState.
  • В дочернем компоненте я использую LaunchedEffect, чтобы определить, когда
    PDF изменяется.
  • Когда он меняется, я вызываю функцию в родительском элементе, передавая PDF
    вверх.
Вот упрощенный фрагмент того, как родитель получает PDF-файл от дочернего элемента:

Код: Выделить всё

composable(InfractionsDestinations.Pending.name) {
PendingScreen(
infractions = uiState.pendingInfractions,
onPDFDisplayRequested = { pdf ->
vm.showPDF(pdf = pdf)
}
)
}
Проблема в том, что теперь и родительский, и дочерний элементы хранят PDF-файл в своем собственном uiState, поскольку он будет использоваться для его отображения, отправки или печати, поэтому его необходимо сохранить. Это нарушает принцип единого источника истины (SSOT).
⚡ Мини-пример проблемы
Дочерняя модель представления:

Код: Выделить всё

data class PendingScreenUiState(
val loading: Boolean = false,
val pdf: PDF? = null
)

class PendingScreenViewModel : ViewModel() {
private val _uiState = MutableStateFlow(PendingScreenUiState())
val uiState: StateFlow
 = _uiState

fun buildPDF(context: Context, infraction: InfractionWithDetails) {
viewModelScope.launch {
val pdfFile = PDFUtils.generateProvisionalPDF(context, infraction)
if (pdfFile.exists()) {
val bulletinPDF = PDF(pdfFile)
_uiState.update { it.copy(pdf = bulletinPDF) }
}
}
}
}
Дочерний составной элемент:

Код: Выделить всё

@Composable
fun PendingScreen(
infractions: List,
vm: PendingScreenViewModel = koinViewModel(),
onPDFDisplayRequested: (PDF) -> Unit
) {
val uiState by vm.uiState.collectAsStateWithLifecycle()

LaunchedEffect(uiState.pdf) {
uiState.pdf?.let { onPDFDisplayRequested(it) }
}

// ... rest of the UI
}
Существует ли более чистая стратегия, которая следует рекомендуемым принципам Compose + MVVM (например, SSOT и подъем состояния) для решения этой ситуации?
Сейчас я чувствую себя вынужденным дублировать PDF-файл как в дочернем, так и в родительском состояниях, что кажется неправильным. Существует ли рекомендуемый шаблон для централизации обработки PDF-файлов в родительском элементе, при этом позволяя каждому дочернему элементу генерировать его в своей собственной модели представления?

Подробнее здесь: https://stackoverflow.com/questions/798 ... assing-par
Ответить

Быстрый ответ

Изменение регистра текста: 
Смайлики
:) :( :oops: :roll: :wink: :muza: :clever: :sorry: :angel: :read: *x)
Ещё смайлики…
   
К этому ответу прикреплено по крайней мере одно вложение.

Если вы не хотите добавлять вложения, оставьте поля пустыми.

Максимально разрешённый размер вложения: 15 МБ.

Вернуться в «Android»