Модификации могут означать разные вещи в зависимости от контекста. В Android-разработке чаще всего речь идёт о следующих типах модификаций:
Модификация данных (изменение состояния)
Модификация UI (Compose Modifiers)
Модификация кода (рефакторинг, оптимизация)
Модификация системы (кастомные прошивки, рут-изменения)
Это изменение переменных, объектов и структур данных во время работы приложения.
class ViewModel : ViewModel() {
private val _state = MutableStateFlow("Привет, мир!")
val state: StateFlow<String> = _state
fun updateText(newText: String) {
_state.value = newText // Модификация состояния
}
}В Jetpack Compose модификации (
Modifier) используются для изменения внешнего вида и поведения UI-элементов. Text(
text = "Привет!",
modifier = Modifier
.padding(16.dp) // Добавляем отступ
.background(Color.Blue) // Меняем фон
.clickable { println("Нажали!") } // Добавляем клик
)
В программировании модификация кода означает его улучшение без изменения основной логики.
fun sum(a: Int, b: Int): Int {
return a + b
}После рефакторинга
fun sum(a: Int, b: Int) = a + b
Это изменения в самой операционной системе Android, например:
- Рут-доступ (
root), позволяющий изменять системные файлы. - Кастомные прошивки (например, LineageOS).
- Изменение build.prop для скрытия рут-доступа.
ro.build.version.sdk=33
Ставь 👍 и забирай 📚 Базу знаний
Please open Telegram to view this post
VIEW IN TELEGRAM
👍1🤔1
MutableState<T> – это обертка для хранения состояния в Jetpack Compose, которая автоматически отслеживает изменения и инициирует рекомпозицию.
Ставь 👍 если знал ответ, 🔥 если нет
Забирай 📚 Базу знаний
Please open Telegram to view this post
VIEW IN TELEGRAM
🔥4👍2
В Android для наложения (перекрытия) элементов друг на друга используется FrameLayout или Box (в Jetpack Compose).
FrameLayout — это контейнер, в котором все вложенные элементы располагаются в левом верхнем углу, но при этом могут накладываться друг на друга.
<FrameLayout
android:layout_width="match_parent"
android:layout_height="match_parent">
<ImageView
android:layout_width="match_parent"
android:layout_height="match_parent"
android:src="@drawable/background" />
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Наложенный текст"
android:textSize="24sp"
android:textColor="#FFFFFF"
android:layout_gravity="center"/>
</FrameLayout>
В Jetpack Compose аналогом
FrameLayout является Box. Он также позволяет располагать элементы друг над другом. Box(
modifier = Modifier.fillMaxSize()
) {
Image(
painter = painterResource(id = R.drawable.background),
contentDescription = "Фон",
modifier = Modifier.fillMaxSize()
)
Text(
text = "Наложенный текст",
fontSize = 24.sp,
color = Color.White,
modifier = Modifier.align(Alignment.Center)
)
}
Ставь 👍 и забирай 📚 Базу знаний
Please open Telegram to view this post
VIEW IN TELEGRAM
👍2
Нет, MutableState в Compose не гарантирует потокобезопасность.
Если несколько потоков одновременно модифицируют состояние, это может привести к состоянию гонки (race condition).
Ставь 👍 если знал ответ, 🔥 если нет
Забирай 📚 Базу знаний
Please open Telegram to view this post
VIEW IN TELEGRAM
👍2🔥2
В Kotlin есть три основных типа коллекций:
List — упорядоченный список элементов.
Set — множество уникальных элементов.
Map — коллекция пар "ключ-значение".
List — это коллекция, в которой можно хранить дубликаты, а элементы доступны по индексу.
val numbers = listOf(1, 2, 3, 4, 5) // Immutable (нельзя изменять)
val mutableNumbers = mutableListOf(1, 2, 3) // Можно изменять
mutableNumbers.add(4) // Добавляем элемент
mutableNumbers.removeAt(1) // Удаляем элемент по индексу
println(mutableNumbers) // [1, 3, 4]
Set — это коллекция, в которой нет дубликатов.
val numbers = setOf(1, 2, 3, 3, 4, 5) // Дубликаты удаляются автоматически
println(numbers) // [1, 2, 3, 4, 5]
val mutableNumbers = mutableSetOf(1, 2, 3)
mutableNumbers.add(3) // Не добавится, потому что уже есть
mutableNumbers.add(4) // Добавится
println(mutableNumbers) // [1, 2, 3, 4]
Map — это структура данных, в которой каждому ключу соответствует одно значение.
val userMap = mapOf(
1 to "Alice",
2 to "Bob",
3 to "Charlie"
) // Immutable
val mutableUserMap = mutableMapOf(1 to "Alice", 2 to "Bob")
mutableUserMap[3] = "Charlie" // Добавляем новый ключ-значение
mutableUserMap.remove(1) // Удаляем элемент по ключу
println(mutableUserMap) // {2=Bob, 3=Charlie}
Ставь 👍 и забирай 📚 Базу знаний
Please open Telegram to view this post
VIEW IN TELEGRAM
👍2🔥1
Jetpack Compose использует асинхронный рендеринг, который проходит несколько этапов:
1. Композиция – анализ и построение дерева UI.
2. Составление Layout – расчет размеров и позиций элементов.
3. Рендеринг – отрисовка UI через Canvas и GPU.
Ставь 👍 если знал ответ, 🔥 если нет
Забирай 📚 Базу знаний
Please open Telegram to view this post
VIEW IN TELEGRAM
🔥2
Да, объём стека изменится, а вот объём кучи останется неизменным (но нагрузка на неё увеличится).
Стек (Stack) — это область памяти для локальных переменных и вызовов функций.
- У каждого потока (Thread) есть свой отдельный стек.
- Размер стека фиксирован и устанавливается при создании потока.
- Чем больше потоков, тем больше памяти выделяется под стеки.
Если размер стека 1 МБ, и мы создаём 100 потоков, то под стеки уйдёт 100 МБ памяти.
Куча (Heap) — это область памяти для объектов.
- Куча общая для всех потоков.
- Новый поток не создаёт отдельную кучу, он использует ту же самую.
- Но больше потоков → больше создаваемых объектов → больше нагрузка на сборщик мусора (GC).
Вывод: Объём кучи не меняется автоматически, но может быстрее заполняться.
Ставь 👍 и забирай 📚 Базу знаний
Please open Telegram to view this post
VIEW IN TELEGRAM
👍6
Jetpack Compose for iOS (в рамках Kotlin Multiplatform) использует:
- Skia – для отрисовки графики (через Compose Runtime).
- Metal/OpenGL – для работы с GPU.
- UIKit – для взаимодействия с iOS-компонентами.
Ставь 👍 если знал ответ, 🔥 если нет
Забирай 📚 Базу знаний
Please open Telegram to view this post
VIEW IN TELEGRAM
🔥4
В Android можно создавать интерфейс без XML с помощью Jetpack Compose или программного кода (View в Kotlin/Java).
Jetpack Compose — это новый способ создания UI в Android без XML, основанный на Kotlin.
@Composable
fun GreetingScreen() {
Column(
modifier = Modifier.fillMaxSize().padding(16.dp),
horizontalAlignment = Alignment.CenterHorizontally
) {
Text(text = "Привет, мир!", fontSize = 24.sp)
Button(onClick = { println("Кнопка нажата") }) {
Text("Нажми меня")
}
}
}
class MainActivity : ComponentActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContent {
GreetingScreen()
}
}
}
Если Jetpack Compose не подходит, можно создать интерфейс программно, без XML, используя стандартные
View. class MainActivity : AppCompatActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
// Создаём контейнер (LinearLayout)
val layout = LinearLayout(this).apply {
orientation = LinearLayout.VERTICAL
gravity = Gravity.CENTER
layoutParams = ViewGroup.LayoutParams(
ViewGroup.LayoutParams.MATCH_PARENT,
ViewGroup.LayoutParams.MATCH_PARENT
)
}
// Создаём текст
val textView = TextView(this).apply {
text = "Привет, мир!"
textSize = 24f
setTextColor(Color.BLACK)
}
// Создаём кнопку
val button = Button(this).apply {
text = "Нажми меня"
setOnClickListener {
textView.text = "Кнопка нажата!"
}
}
// Добавляем элементы в контейнер
layout.addView(textView)
layout.addView(button)
// Устанавливаем UI
setContentView(layout)
}
}Ставь 👍 и забирай 📚 Базу знаний
Please open Telegram to view this post
VIEW IN TELEGRAM
👍6🔥2
Каждый MutableState имеет подписчиков (observers), которые автоматически уведомляются об изменениях.
При обновлении значения, Compose отправляет сигнал о необходимости рекомпозиции тем элементам, которые используют это состояние.
Ставь 👍 если знал ответ, 🔥 если нет
Забирай 📚 Базу знаний
Please open Telegram to view this post
VIEW IN TELEGRAM
👍2🔥2
В
interface можно определять свойства (val или var), но их реализация зависит от того, есть ли у них get и set. В интерфейсе можно объявить
val (только для чтения) или var (для чтения и записи), но без инициализации. interface User {
val name: String // Объявляем свойство, но не реализуем
var age: Int // Может изменяться, но без начального значения
}Использование в классе
class Person(override val name: String) : User {
override var age: Int = 25 // Обязательно реализовать
}Можно задать кастомный геттер прямо в интерфейсе.
interface User {
val name: String
val greeting: String
get() = "Привет, $name!" // Реализация внутри интерфейса
}Использование в классе
class Person(override val name: String) : User
fun main() {
val user = Person("Андрей")
println(user.greeting) // Привет, Андрей!
}
Если в интерфейсе объявить
var, то нельзя задать реализацию геттера и сеттера — их должен реализовать класс. interface User {
var age: Int // Только объявление, без реализации
}Использование в классе
class Person : User {
override var age: Int = 30 // Реализуем свойство
}В
interface нельзя использовать field (бэкинг-поле), потому что у интерфейсов нет состояния. interface User {
var age: Int
get() = field // Ошибка! Нельзя использовать `field` в интерфейсе
set(value) { field = value }
}Ставь 👍 и забирай 📚 Базу знаний
Please open Telegram to view this post
VIEW IN TELEGRAM
👍5
Возвращаемый тип становится Any, потому что функция может вернуть либо String, либо корутину в приостановленном состоянии.
Ставь 👍 если знал ответ, 🔥 если нет
Забирай 📚 Базу знаний
Please open Telegram to view this post
VIEW IN TELEGRAM
🔥3
В Kotlin нет
switch, но его заменяет более мощный оператор when. Простой пример (аналог
switch-case) fun getDayName(day: Int): String {
return when (day) {
1 -> "Понедельник"
2 -> "Вторник"
3 -> "Среда"
4 -> "Четверг"
5 -> "Пятница"
6 -> "Суббота"
7 -> "Воскресенье"
else -> "Некорректный день"
}
}
fun main() {
println(getDayName(3)) // Среда
}when без else (если учтены все случаи) fun getStatus(code: Int): String = when (code) {
200 -> "OK"
404 -> "Not Found"
500 -> "Server Error"
}Несколько значений в одном
case fun isWeekend(day: Int): Boolean {
return when (day) {
6, 7 -> true // Оба значения работают как один case
else -> false
}
}Можно проверять логические выражения, а не просто числа.
fun checkNumber(x: Int): String {
return when {
x < 0 -> "Отрицательное число"
x == 0 -> "Ноль"
x > 0 -> "Положительное число"
else -> "Ошибка"
}
}Использование
when без аргумента fun describe(obj: Any): String {
return when {
obj is String -> "Это строка"
obj is Int -> "Это число"
obj is Boolean -> "Это логический тип"
else -> "Неизвестный тип"
}
}when можно использовать как выражение, возвращая результат: val message = when (val code = 404) {
200 -> "OK"
404 -> "Not Found"
else -> "Unknown"
}
println(message) // Not FoundСтавь 👍 и забирай 📚 Базу знаний
Please open Telegram to view this post
VIEW IN TELEGRAM
👍4🤯1👾1
Создать suspend-функцию можно, добавив suspend перед fun.
suspend-функции нельзя вызывать напрямую из обычных функций, только из корутин.
Ставь 👍 если знал ответ, 🔥 если нет
Забирай 📚 Базу знаний
Please open Telegram to view this post
VIEW IN TELEGRAM
👍5🤯5😁3🔥1
Google постоянно ограничивает работу сервисов в Android, чтобы:
Уменьшить расход батареи
Оптимизировать использование памяти
Защитить пользователя от фоновых процессов, "убивающих" производительность
Сервис нельзя запустить из фона, если приложение не активно.
startService(Intent) выдаст ошибку, если приложение не на переднем плане. 1. Использовать Foreground Service (с уведомлением).
2. Использовать JobIntentService / WorkManager.
class MyForegroundService : Service() {
override fun onCreate() {
super.onCreate()
val notification = NotificationCompat.Builder(this, "channelId")
.setContentTitle("Сервис работает")
.setSmallIcon(R.drawable.ic_launcher_foreground)
.build()
startForeground(1, notification) // Запускаем сервис в Foreground
}
override fun onBind(intent: Intent?): IBinder? = null
}Если сервис запущен из фона (например, через
BroadcastReceiver), он не запустится. Исключение – если сервис работает в Foreground или с AlarmManager.
1. Использовать WorkManager (лучший вариант).
2. Использовать Foreground Service с уведомлением.
3. Использовать AlarmManager для периодических задач.
В спящем режиме (
Doze Mode) система отключает сервисы. Приложения не могут выполнять фоновые задачи.
Использовать Foreground Service.
Использовать JobScheduler / WorkManager.
Использовать Firebase Cloud Messaging (FCM) для пробуждения приложения.
Если пользователь смахнул приложение из списка недавних, фоновые сервисы будут убиты.
Решение → Foreground Service +
startForeground() или JobScheduler. Ставь 👍 и забирай 📚 Базу знаний
Please open Telegram to view this post
VIEW IN TELEGRAM
👍6
suspend-функции можно запускать только из корутин.
Можно вызывать их из:
1. launch {} или async {} в CoroutineScope
2. Другое suspend-функции`
3. runBlocking {} (для тестирования в main-потоке)
Ставь 👍 если знал ответ, 🔥 если нет
Забирай 📚 Базу знаний
Please open Telegram to view this post
VIEW IN TELEGRAM
👍3🤯2🔥1😁1🤔1
Анонимный класс внутри
inline-функции будет инстанцироваться при каждом вызове функции, что ломает цель inline — избавляться от накладных расходов на объекты. Анонимный класс — это класс без имени, который можно создать с помощью
object : Interface {}. interface ClickListener {
fun onClick()
}
fun main() {
val listener = object : ClickListener {
override fun onClick() {
println("Кнопка нажата!")
}
}
listener.onClick()
}Если мы создадим анонимный класс внутри
inline-функции, он будет создаваться каждый раз при вызове функции! inline fun setClickListener(action: () -> Unit) {
val listener = object : ClickListener {
override fun onClick() {
action()
}
}
listener.onClick()
}
fun main() {
setClickListener { println("Нажато!") }
}Ошибка компиляции
Inline function cannot contain object expressions
Если нужно использовать
inline, можно передавать лямбду вместо анонимного класса. Рабочий вариант
inline fun setClickListener(noinline action: () -> Unit): ClickListener {
return object : ClickListener {
override fun onClick() {
action()
}
}
}
fun main() {
val listener = setClickListener { println("Нажато!") }
listener.onClick()
}Ставь 👍 и забирай 📚 Базу знаний
Please open Telegram to view this post
VIEW IN TELEGRAM
👍3
Рекомпозиция управляется Android Choreographer, который работает с VSYNC.
Процесс:
1. Изменение MutableState ставит флаг "UI требует перерисовки".
2. Choreographer ждет ближайший VSYNC и запускает рекомпозицию.
3. Перерисовываются только измененные элементы UI.
Ставь 👍 если знал ответ, 🔥 если нет
Забирай 📚 Базу знаний
Please open Telegram to view this post
VIEW IN TELEGRAM
🔥4👍2🤯1
Android 5.0 Lollipop стал огромным обновлением по сравнению с Android 4.x, изменив интерфейс, архитектуру и производительность.
Android 4: использовал Holo UI (чёрно-серый стиль с минимализмом).
Android 5: представил Material Design — новый визуальный стиль с тенями, анимациями и цветными кнопками.
<com.google.android.material.floatingactionbutton.FloatingActionButton
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:src="@drawable/ic_add"
app:backgroundTint="@color/colorAccent"/>
Android 4: использовал Dalvik (Just-in-Time, JIT) — код компилировался во время работы приложения.
Android 5: перешёл на ART (Ahead-of-Time, AOT) — код компилируется один раз при установке.
Android 4: уведомления были простыми и появлялись только в статус-баре.
Android 5: представил Heads-up Notifications (всплывающие уведомления).
val notification = NotificationCompat.Builder(context, "channel_id")
.setContentTitle("Новое сообщение")
.setContentText("Привет, как дела?")
.setPriority(NotificationCompat.PRIORITY_HIGH) // Heads-up уведомление
.setSmallIcon(R.drawable.ic_message)
.build()
Android 4: только 32-битная архитектура.
Android 5: появилась поддержка 64-битных процессоров, что улучшило производительность и работу с памятью.
Android 4: не имел централизованного контроля за энергопотреблением.
Android 5: представил Project Volta, который продлевает жизнь батареи.
val jobScheduler = getSystemService(JobScheduler::class.java)
val jobInfo = JobInfo.Builder(1, ComponentName(this, MyJobService::class.java))
.setRequiresCharging(true) // Выполнить только при зарядке
.build()
jobScheduler.schedule(jobInfo)
Android 4: старые приложения в "Недавних" выглядели как список окон.
Android 5: приложения теперь отображаются в виде стопки карт (Card Stack UI).
Шифрование устройства включено по умолчанию (Android 5).
SELinux (Security-Enhanced Linux) теперь работает в принудительном (
enforcing) режиме. Добавлен Smart Lock → автоматическая разблокировка устройства по Bluetooth / Wi-Fi / лицу.
Android 5 впервые добавил поддержку Android Wear (умные часы) и Android TV.
Ставь 👍 и забирай 📚 Базу знаний
Please open Telegram to view this post
VIEW IN TELEGRAM
😁3👍2
Suspend-функция не блокирует поток, а передает управление Continuation-объекту.
Функция "узнает" о приостановке через:
- Фрейм Continuation: если вызвана другая suspend-функция, текущая приостанавливает свое выполнение.
- Корутинный диспетчер: приостановка возможна, если выполнение ушло в другой поток (withContext).
- Возвращение специального маркера COROUTINE_SUSPENDED: сигнализирует Kotlin Runtime, что выполнение отложено.
Ставь 👍 если знал ответ, 🔥 если нет
Забирай 📚 Базу знаний
Please open Telegram to view this post
VIEW IN TELEGRAM
🔥5🤯3