KT Kotlin  ·  30 вопросов  ·  ~85 мин  ·  ⏱ Таймер 25:00  ·  Сложный  ·  👥 2 прошли

Android: жизненный цикл и состояние

Тест о том, что происходит с состоянием Android-приложения при пересоздании экрана, уходе процесса и смене владельца жизненного цикла. Придётся отличать данные ViewModel от сохранённого состояния, замечать утечки контекста и разбирать конкурентные обновления.

Отвечено: 0 из 30
--:--
0%
💡 Инструкция: Выберите один ответ из пяти. На 30 вопросов отведено 85 минут. В каждом задании верен только один вариант. После завершения будут показаны общий результат и 6 тематических шкал.
Вопрос 1 из 30
Почему поведение «StateFlow в viewModelScope» не является случайностью?
KotlinСостояние во ViewModel · StateFlow в viewModelScope
// На ревью требуется объяснить причину поведения.
import kotlinx.coroutines.flow.*
class UserViewModel(private val repo: Repo) : ViewModel() {
    val state = repo.users.stateIn(
        viewModelScope,
        SharingStarted.WhileSubscribed(5_000),
        emptyList()
    )
}
Вопрос 2 из 30
Что следует изменить прежде всего во фрагменте «Минимальное состояние поиска»?
KotlinСохранённое состояние · Минимальное состояние поиска
// Сохраните назначение фрагмента, но укрепите его контракт.
class SearchViewModel(private val saved: SavedStateHandle) : ViewModel() {
    var query: String
        get() = saved["query"] ?: ""
        set(value) { saved["query"] = value }
}
Вопрос 3 из 30
Какой редкий случай способен сломать наивную трактовку «Activity в глобальном кеше»?
Вопрос 4 из 30
Предложенная правка для «Реальное пересоздание Activity» звучит так: Добавить тест перехода в background и process-death-инструментированный сценарий для критичного восстановления. Какой недостаток важнее обсудить?
Вопрос 5 из 30
Какие границы ответственности здесь удачны?
KotlinАрхитектура и конкурентность · Экранное состояние по восстановленному id
// Проследите фактическое выполнение без изменения кода.
import kotlinx.coroutines.flow.*
class ScreenModel(
    private val repo: Repo,
    saved: SavedStateHandle
) : ViewModel() {
    private val id = requireNotNull(saved.get<String>("id"))
    val state = repo.observe(id)
        .stateIn(viewModelScope, SharingStarted.WhileSubscribed(5_000), Loading)
}
Вопрос 6 из 30
Что происходит, когда экран переходит ниже STARTED?
KotlinЖизненный цикл Android · Сбор потока в STARTED
// Проследите фактическое выполнение без изменения кода.
import kotlinx.coroutines.*
lifecycleScope.launch {
    repeatOnLifecycle(Lifecycle.State.STARTED) {
        viewModel.state.collect { render(it) }
    }
}
Вопрос 7 из 30
Где поведение «Минимальное состояние поиска» требует отдельной проверки?
Вопрос 8 из 30
Предложенная правка для «Activity в глобальном кеше» звучит так: Передать applicationContext в компонент, которому действительно нужен системный ресурс, либо внедрить узкий интерфейс. Какой недостаток важнее обсудить?
Вопрос 9 из 30
Что проверяет такой тест лучше обычного unit-теста ViewModel?
KotlinТестирование и инструменты · Реальное пересоздание Activity
// Проследите фактическое выполнение без изменения кода.
@Test fun state_survives_recreation() {
    scenario.onActivity { it.type("kotlin") }
    scenario.recreate()
    scenario.onActivity { assertEquals("kotlin", it.queryText()) }
}
Вопрос 10 из 30
Какой контракт определяет наблюдаемый результат «Экранное состояние по восстановленному id»?
KotlinАрхитектура и конкурентность · Экранное состояние по восстановленному id
// На ревью требуется объяснить причину поведения.
import kotlinx.coroutines.flow.*
class ScreenModel(
    private val repo: Repo,
    saved: SavedStateHandle
) : ViewModel() {
    private val id = requireNotNull(saved.get<String>("id"))
    val state = repo.observe(id)
        .stateIn(viewModelScope, SharingStarted.WhileSubscribed(5_000), Loading)
}
Вопрос 11 из 30
Какое объяснение результата «Сбор потока в STARTED» выдерживает проверку соседними случаями?
KotlinЖизненный цикл Android · Сбор потока в STARTED
// На ревью требуется объяснить причину поведения.
import kotlinx.coroutines.*
lifecycleScope.launch {
    repeatOnLifecycle(Lifecycle.State.STARTED) {
        viewModel.state.collect { render(it) }
    }
}
Вопрос 12 из 30
Как превратить неявное предположение в проверяемый контракт «StateFlow в viewModelScope»?
KotlinСостояние во ViewModel · StateFlow в viewModelScope
// Сохраните назначение фрагмента, но укрепите его контракт.
import kotlinx.coroutines.flow.*
class UserViewModel(private val repo: Repo) : ViewModel() {
    val state = repo.users.stateIn(
        viewModelScope,
        SharingStarted.WhileSubscribed(5_000),
        emptyList()
    )
}
Вопрос 13 из 30
Каков фактический результат выполнения фрагмента «Activity в глобальном кеше»?
KotlinУтечки контекста · Activity в глобальном кеше
// Проследите фактическое выполнение без изменения кода.
object ImageCache {
    var context: Context? = null
}

class MainActivity : Activity() {
    override fun onCreate(state: Bundle?) {
        super.onCreate(state)
        ImageCache.context = this
    }
}
Вопрос 14 из 30
Какое объяснение результата «Реальное пересоздание Activity» выдерживает проверку соседними случаями?
KotlinТестирование и инструменты · Реальное пересоздание Activity
// На ревью требуется объяснить причину поведения.
@Test fun state_survives_recreation() {
    scenario.onActivity { it.type("kotlin") }
    scenario.recreate()
    scenario.onActivity { assertEquals("kotlin", it.queryText()) }
}
Вопрос 15 из 30
Какую правку выбрать, чтобы сохранить назначение «Экранное состояние по восстановленному id» и убрать хрупкость?
KotlinАрхитектура и конкурентность · Экранное состояние по восстановленному id
// Сохраните назначение фрагмента, но укрепите его контракт.
import kotlinx.coroutines.flow.*
class ScreenModel(
    private val repo: Repo,
    saved: SavedStateHandle
) : ViewModel() {
    private val id = requireNotNull(saved.get<String>("id"))
    val state = repo.observe(id)
        .stateIn(viewModelScope, SharingStarted.WhileSubscribed(5_000), Loading)
}
Вопрос 16 из 30
Какой рефакторинг делает поведение «Сбор потока в STARTED» предсказуемее?
KotlinЖизненный цикл Android · Сбор потока в STARTED
// Сохраните назначение фрагмента, но укрепите его контракт.
import kotlinx.coroutines.*
lifecycleScope.launch {
    repeatOnLifecycle(Lifecycle.State.STARTED) {
        viewModel.state.collect { render(it) }
    }
}
Вопрос 17 из 30
Какой тест лучше всего защищает край контракта «StateFlow в viewModelScope»?
Вопрос 18 из 30
Какую обратную сторону имеет решение для «Минимальное состояние поиска»: Сохранять идентификатор, фильтр или черновик, а тяжёлую модель заново загружать из репозитория?
Вопрос 19 из 30
Какой рефакторинг делает поведение «Реальное пересоздание Activity» предсказуемее?
KotlinТестирование и инструменты · Реальное пересоздание Activity
// Сохраните назначение фрагмента, но укрепите его контракт.
@Test fun state_survives_recreation() {
    scenario.onActivity { it.type("kotlin") }
    scenario.recreate()
    scenario.onActivity { assertEquals("kotlin", it.queryText()) }
}
Вопрос 20 из 30
Какой контрпример точнее всего показывает границу «Экранное состояние по восстановленному id»?
Вопрос 21 из 30
Какой соседний случай отличает устойчивое решение «Сбор потока в STARTED» от удачного примера?
Вопрос 22 из 30
Какова практическая цена решения «StateFlow в viewModelScope»: Передавать application-safe зависимости, держать интерфейс-состояние immutable и не помещать View/Activity/Context в долгоживущие поля?
Вопрос 23 из 30
Какую задачу решает SavedStateHandle?
KotlinСохранённое состояние · Минимальное состояние поиска
// Проследите фактическое выполнение без изменения кода.
class SearchViewModel(private val saved: SavedStateHandle) : ViewModel() {
    var query: String
        get() = saved["query"] ?: ""
        set(value) { saved["query"] = value }
}
Вопрос 24 из 30
Какое правило определяет поведение фрагмента «Activity в глобальном кеше»?
KotlinУтечки контекста · Activity в глобальном кеше
// На ревью требуется объяснить причину поведения.
object ImageCache {
    var context: Context? = null
}

class MainActivity : Activity() {
    override fun onCreate(state: Bundle?) {
        super.onCreate(state)
        ImageCache.context = this
    }
}
Вопрос 25 из 30
В «Экранное состояние по восстановленному id» выбрали решение: Определить политику повторной загрузки после паузы, обрабатывать ошибку upstream до stateIn и делать состояния неизменяемыми. Какова его реальная цена?
Вопрос 26 из 30
Что станет новой точкой внимания после изменения «Сбор потока в STARTED»: Собирать интерфейс-потоки через repeatOnLifecycle/collectAsStateWithLifecycle, а не запускать вечный collector без остановки?
Вопрос 27 из 30
Что даёт `viewModelScope` этой модели?
KotlinСостояние во ViewModel · StateFlow в viewModelScope
// Проследите фактическое выполнение без изменения кода.
import kotlinx.coroutines.flow.*
class UserViewModel(private val repo: Repo) : ViewModel() {
    val state = repo.users.stateIn(
        viewModelScope,
        SharingStarted.WhileSubscribed(5_000),
        emptyList()
    )
}
Вопрос 28 из 30
Почему поведение «Минимальное состояние поиска» не является случайностью?
KotlinСохранённое состояние · Минимальное состояние поиска
// На ревью требуется объяснить причину поведения.
class SearchViewModel(private val saved: SavedStateHandle) : ViewModel() {
    var query: String
        get() = saved["query"] ?: ""
        set(value) { saved["query"] = value }
}
Вопрос 29 из 30
Какая правка устраняет причину риска в «Activity в глобальном кеше», а не только его проявление?
KotlinУтечки контекста · Activity в глобальном кеше
// Сохраните назначение фрагмента, но укрепите его контракт.
object ImageCache {
    var context: Context? = null
}

class MainActivity : Activity() {
    override fun onCreate(state: Bundle?) {
        super.onCreate(state)
        ImageCache.context = this
    }
}
Вопрос 30 из 30
На каком входе или состоянии граница «Реальное пересоздание Activity» становится заметной?

Ответьте на все 30 вопросов, чтобы получить результат

🔗 Встроить тест на свой сайт (iframe)

Скопируйте код и вставьте в любое место на вашем сайте:

Также доступна прямая ссылка на embed-страницу