Категория > Новости > Android: подмена системных диалогов и утечки памяти - «Новости»
Android: подмена системных диалогов и утечки памяти - «Новости»12-01-2021, 00:00. Автор: Павел |
3. Проверь код навигации приложения. При использовании паттерна «Одна активность», когда в приложении есть всего одна активность (Activity), а все экраны представляют собой фрагменты (Fragment), ты можешь заметить, что при перемещении на новый фрагмент старый фрагмент не уничтожается. Это стандартное поведение фрагментов, поэтому заботиться об освобождении памяти должен ты сам. Для этого достаточно самостоятельно уничтожать все View в методе Другие советы:
Kotlin и видимость APIMastering API Visibility in Kotlin — статья о том, как сделать интерфейсы библиотек как можно более закрытыми, сохранив гибкость, возможности тестирования и возможность взаимодействовать с кодом на Java.
Что такое ArrayMap и SparseArrayAll you need to know about ArrayMap & SparseArray — статья об ArrayMap и SparseArray, двух фирменных, но не так хорошо известных коллекциях Android. Обе коллекции по сути аналоги HashMap из Java с тем исключением, что они созданы специально, чтобы минимизировать потребление оперативной памяти. В отличие от HashMap, который для хранения каждого объекта создает новый объект и сохраняет его в массиве, ArrayMap не создает дополнительный объект, но использует два массива: mHashes для последовательного хранения хешей ключей и mArray для хранения ключей и их значений (друг за другом). Начальный размер первого — четыре, второго — восемь. Анатомия ArrayMap При добавлении элемента ArrayMap сначала добавляет его хеш в первый массив, а затем ключ и значение во второй массив, где индекс ключа высчитывается как индекс хеша в массиве mHashes, умноженный на два, а индекс значения как индекс ключа плюс один. В случае коллизии (когда два разных ключа имеют одинаковый хеш) ArrayMap производит линейный поиск ключа в mArray и, если он не найден, добавляет новый хеш в mHashes и новые ключ:значение в mArray. При достижении предельного размера массивов ArrayMap копирует их в новый массив, размер которого высчитывается так: SparseArray представляет собой тот же ArrayMap, но предназначенный для работы с типами данных, где ключ — это int, а значение может быть либо объектом, либо простым типом данных: int, long, boolean (SparseIntArray, SparseLongArray, SparseBooleanArray). В итоге SparseArray нет необходимости хранить обертки над простыми типами данных. Благодаря избавлению от необходимости хранить дополнительный объект для каждого элемента, ArrayMap оказывается примерно на 25% экономнее HashMap, а SparseArray почти в два раза экономнее. HashMap vs ArrayMap vs SparseArray: использование памяти для 1000 объектов В то же время ArrayMap и SparseArray в целом в два раза медленнее HashMap. HashMap vs ArrayMap vs SparseArray: рандомные операции чтения Выводы:
RecyclerView с помощью Jetpack ComposeHow to make a RecyclerView in Jetpack Compose — краткая заметка о том, как создать собственный RecyclerView, используя библиотеку Jetpack Compose. RecyclerView — известный и очень популярный элемент интерфейса Android, позволяющий создать динамически формируемый (бесконечный) список элементов с ленивой загрузкой и переиспользуемыми элементами UI. Говоря простыми словами: RecyclerView — это быстрый список из произвольного количества элементов, который будет расходовать память только на те элементы, которые в данный момент находятся на экране. RecyclerView — очень мощный и сложный инструмент. Чтобы создать список с его помощью, необходимо создать сам RecyclerView, подключить к нему адаптер, который будет наполнять его элементами, подключить менеджер лейаутов и создать один или несколько viewHolder’ов, которые будут хранить графическое представление элементов списка. А теперь посмотрим, как создать аналог RecyclerView с использованием фреймворка Jetpack Compose:
data class ItemViewState(
val text: String
)
@Composable
fun MyComposeList(
modifier: Modifier = Modifier,
itemViewStates: List<ItemViewState>
) {
LazyColumnFor(modifier = modifier, items = itemViewStates) { viewState ->
MyListItem(itemViewState = viewState)
}
}
@Composable
fun MyListItem(itemViewState: ItemViewState) {
Text(text = itemViewState.text)
}
Это действительно все. Валидация форм с помощью Kotlin FlowUsing Flows for Form Validation in Android — короткая заметка о том, как реализовать валидацию форм с помощью Kotlin Flow. Интересна в первую очередь в качестве простой и наглядной демонстрации работы недавно появившегося StateFlow. Допустим, у нас есть форма с тремя полями: First Name, Password и User Id. Наша задача — сделать так, чтобы кнопка Submit активировалась лишь в том случае, если поле First Name содержит только символы латинского алфавита, поле Password содержит как минимум восемь символов, а поле User Id содержит хотя бы один символ подчеркивания. Для хранения текущего значения поля будем использовать StateFlow:
private val _firstName = MutableStateFlow("")
private val _password = MutableStateFlow("")
private val _userID = MutableStateFlow("")
Дополнительно создадим три метода, чтобы записывать значения в эти StateFlow:
fun setFirstName(name: String) {
_firstName.value = name
}
fun setPassword(password: String) {
_password.value = password
}
fun setUserId(id: String) {
_userID.value = id
}
Теперь объединим все три StateFlow в один Flow, который будет отдавать только значения true или false:
val isSubmitEnabled: Flow<Boolean> = combine(_firstName, _password, _userID) { firstName, password, userId ->
val regexString = "[a-zA-Z]+"
val isNameCorrect = firstName.matches(regexString.toRegex())
val isPasswordCorrect = password.length > 8
val isUserIdCorrect = userId.contains("_")
return@combine isNameCorrect and isPasswordCorrect and isUserIdCorrect
}
Этот код будет запускаться каждый раз, когда состояние любого из трех StateFlow изменится. Теперь осталось только привязать три первых StateFlow к полям ввода:
private fun initListeners() {
editText_name.addTextChangedListener {
viewModel.setFirstName(it.toString())
}
editText_password.addTextChangedListener {
viewModel.setPassword(it.toString())
}
editText_user.addTextChangedListener {
viewModel.setUserId(it.toString())
}
}
А состояние кнопки Submit привязать к полученному в результате преобразования Flow:
private fun collectFlow() {
lifecycleScope.launch {
viewModel.isSubmitEnabled.collect { value ->
submit_button.isEnabled = value
}
}
}
Что делает весь этот код? При изменении любого из полей ввода будет автоматически изменено значение одного из трех StateFlow. Это, в свою очередь, повлечет за собой запуск функции Инструменты
Библиотеки
Перейти обратно к новости |