Лямбда-выражения представляют собой компактный способ представления анонимных функций, который особенно полезен для создания коротких блоков выполнения кода, предназначенных для последующей передачи другим функциям. Лямбды широко используются для упрощения работы с коллекциями, потоками данных, асинхронным кодом и в ситуациях, где требуется функциональный интерфейс.
Были введены в Java 8 и являются частью усилий по добавлению функциональных возможностей в язык. Лямбды в Java чаще всего используются с функциональными интерфейсами, которые являются интерфейсами с одним абстрактным методом.
(parameters) -> expression
или
(parameters) -> { statements; }Поддерживает более гибкие и выразительные лямбды по сравнению с Java. Лямбды могут использоваться как с функциональными интерфейсами, так и в качестве части синтаксиса языка, благодаря чему Kotlin особенно удобен для функционального программирования.
{ parameters -> code body }Лямбда без параметров
{ println("Hello, World!") } Лямбда с одним параметром
{ a: Int -> a * a } Лямбда с несколькими параметрами
{ a: Int, b: Int -> a + b } Лямбда с телом, содержащим несколько выражений
{ s: String ->
println(s)
s.length
}Ставь 👍 и забирай 📚 Базу знаний
Please open Telegram to view this post
VIEW IN TELEGRAM
👍4
2. Дедлок: блокировка потоков, когда каждый поток ждёт ресурсы, занятые другим потоком.
3. Утечки памяти: при неправильной синхронизации объектов или их несвоевременном освобождении.
Ставь 👍 если знал ответ, 🔥 если нет
Забирай 📚 Базу знаний
Please open Telegram to view this post
VIEW IN TELEGRAM
🔥8👍2
Dagger – это фреймворк для внедрения зависимостей (DI), который помогает управлять созданием и передачей объектов в приложении. В основе Dagger лежат граф зависимостей, который состоит из следующих ключевых элементов:
@Module – это класс, который предоставляет зависимости. @Provides – аннотация, указывающая, что метод создаёт объект для графа Dagger. @Module
class NetworkModule {
@Provides
fun provideRetrofit(): Retrofit {
return Retrofit.Builder()
.baseUrl("https://api.example.com")
.build()
}
}
@Inject в конструкторе – позволяет Dagger автоматически создавать объект без @Module. class ApiService @Inject constructor(private val retrofit: Retrofit) {
fun fetchData() { /*...*/ }
}@Component – это интерфейс, который соединяет модули и классы, где нужны зависимости. @Component(modules = [NetworkModule::class])
interface AppComponent {
fun inject(activity: MainActivity) // Указываем, куда внедрять зависимости
}
Используется для создания одного экземпляра объекта на всё приложение.
@Singleton
@Component(modules = [NetworkModule::class])
interface AppComponent
Если у нас есть интерфейс и его реализация, лучше использовать
@Binds вместо @Provides. interface Repository {
fun getData(): String
}
class RepositoryImpl @Inject constructor() : Repository {
override fun getData() = "Data from repository"
}
@Module
abstract class RepositoryModule {
@Binds
abstract fun bindRepository(repo: RepositoryImpl): Repository
}Если нужно создать зависимости с разными областями жизни (например,
Activity, Fragment), используют @Subcomponent. @Subcomponent
interface ActivityComponent {
fun inject(activity: MainActivity)
}
Ставь 👍 и забирай 📚 Базу знаний
Please open Telegram to view this post
VIEW IN TELEGRAM
👍6
Ставь 👍 если знал ответ, 🔥 если нет
Забирай 📚 Базу знаний
Please open Telegram to view this post
VIEW IN TELEGRAM
🔥3
Jetpack Compose – это декларативный UI-фреймворк от Google для создания интерфейсов в Android. Вместо традиционных
XML + View в Compose используется функции-компоненты, которые описывают UI. Декларативный подход – UI создаётся через функции, без XML.
еактивность – UI автоматически обновляется, если данные изменились.
Компонентный подход – UI состоит из маленьких, переиспользуемых функций.
Composable-функции (
@Composable) – основной строительный блок Compose. Вместо
Activity и Fragment с findViewById() используется @Composable-функции. @Composable
fun Greeting(name: String) {
Text(text = "Привет, $name!")
}
@Composable
fun MyScreen() {
Column {
Greeting("Андрей")
Greeting("Мария")
}
}
@Preview
@Composable
fun PreviewMyScreen() {
MyScreen()
}
Jetpack Compose использует реактивный подход, где UI обновляется при изменении состояния.
@Composable
fun Counter() {
var count by remember { mutableStateOf(0) } // Реактивное состояние
Column {
Text("Счётчик: $count")
Button(onClick = { count++ }) {
Text("Увеличить")
}
}
}
Текст
Text(text = "Привет, мир!", fontSize = 20.sp)
Кнопка
Button(onClick = { /* действие */ }) {
Text("Нажми меня")
}Ввод текста (
TextField) var text by remember { mutableStateOf("") }
TextField(value = text, onValueChange = { text = it })Размещение элементов (вертикально/горизонтально)
Column {
Text("Первый элемент")
Text("Второй элемент")
}Row {
Text("Слева")
Text("Справа")
}Compose работает с MVVM через
ViewModel и LiveData / StateFlow. class MyViewModel : ViewModel() {
private val _count = MutableStateFlow(0)
val count: StateFlow<Int> = _count
fun increment() {
_count.value++
}
}@Composable
fun CounterScreen(viewModel: MyViewModel = viewModel()) {
val count by viewModel.count.collectAsState()
Column {
Text("Счётчик: $count")
Button(onClick = { viewModel.increment() }) {
Text("Добавить")
}
}
}
Вместо
Fragment используется NavController. @Composable
fun MyApp() {
val navController = rememberNavController()
NavHost(navController, startDestination = "home") {
composable("home") { HomeScreen(navController) }
composable("details") { DetailsScreen() }
}
}
Теперь можно перейти на другой экран так
navController.navigate("details")Ставь 👍 и забирай 📚 Базу знаний
Please open Telegram to view this post
VIEW IN TELEGRAM
👍8🔥1
Для внедрения роутера в презентер можно использовать Dependency Injection (например, Dagger, Hilt или Koin). Это позволяет передать роутер в презентер через конструктор или метод, обеспечивая слабую связность и удобство тестирования.
Ставь 👍 если знал ответ, 🔥 если нет
Забирай 📚 Базу знаний
Please open Telegram to view this post
VIEW IN TELEGRAM
👍1🔥1
Этот инструмент показывает время, затраченное на отрисовку каждого кадра. Использование этого инструмента позволяет выявить "тяжелые" кадры и измерить улучшения после оптимизации.
Предоставляет набор инструментов для анализа производительности приложения.
Создание и использование тестов производительности помогает количественно оценить улучшения. Вы можете использовать библиотеку Jetpack Benchmark для создания и выполнения тестов производительности.
build.gradle:dependencies {
androidTestImplementation "androidx.benchmark:benchmark-junit4:1.1.0"
androidTestImplementation "androidx.test:runner:1.3.0"
androidTestImplementation "androidx.test:rules:1.3.0"
}import androidx.benchmark.junit4.BenchmarkRule
import androidx.test.ext.junit.runners.AndroidJUnit4
import org.junit.Rule
import org.junit.Test
import org.junit.runner.RunWith
@RunWith(AndroidJUnit4::class)
class ExampleBenchmark {
@get:Rule
val benchmarkRule = BenchmarkRule()
@Test
fun myFunctionBenchmark() {
benchmarkRule.measureRepeated {
// Вызов вашей функции или кода для тестирования производительности
myFunction()
}
}
}
Используйте журналирование для измерения времени выполнения определенных операций.
val startTime = System.currentTimeMillis()
// Ваш код
val endTime = System.currentTimeMillis()
Log.d("Performance", "Время выполнения: ${endTime - startTime} мс")
StrictMode помогает обнаружить операции, которые могут замедлить работу приложения, такие как работа с сетью или базой данных в главном потоке.
if (BuildConfig.DEBUG) {
StrictMode.setThreadPolicy(
StrictMode.ThreadPolicy.Builder()
.detectAll()
.penaltyLog()
.build()
)
StrictMode.setVmPolicy(
StrictMode.VmPolicy.Builder()
.detectAll()
.penaltyLog()
.build()
)
}Systrace позволяет собирать и анализировать трассировки производительности системы, предоставляя детализированные данные о времени выполнения различных операций.
adb shell am broadcast -a com.android.systemui.screenshot.ScreenshotService.ACTION_SYSTRACE.Ставь 👍 и забирай 📚 Базу знаний
Please open Telegram to view this post
VIEW IN TELEGRAM
👍3
Состояние гонки (race condition) возникает, когда два или более потока одновременно пытаются получить доступ к одному и тому же ресурсу. Это приводит к некорректным результатам, если доступ и изменения не синхронизированы.
Ставь 👍 если знал ответ, 🔥 если нет
Забирай 📚 Базу знаний
Please open Telegram to view this post
VIEW IN TELEGRAM
🔥3👍2
В Kotlin Flow есть два специальных вида потоков для управления состоянием и передачей данных:
StateFlow — используется для хранения и отслеживания состояния.
SharedFlow — используется для многократной отправки данных нескольким подписчикам.
Теперь разберёмся в деталях.
SharedFlow — это горячий (hot) поток, который можно использовать для передачи данных нескольким подписчикам. Он не хранит состояние и просто раздаёт значения подписчикам в реальном времени.
- Позволяет многим подписчикам получать одни и те же данные.
- Может буферизировать значения (хранить их для новых подписчиков).
- Может повторять последние значения (replay) для новых подписчиков.
- Может накапливать данные и работать как очередь событий.
import kotlinx.coroutines.*
import kotlinx.coroutines.flow.*
fun main() = runBlocking {
val sharedFlow = MutableSharedFlow<Int>(replay = 2) // Будет повторять последние 2 значения для новых подписчиков
launch {
for (i in 1..5) {
sharedFlow.emit(i)
delay(100)
}
}
launch {
delay(150) // Подписываемся чуть позже
sharedFlow.collect { println("Первый подписчик получил: $it") }
}
launch {
delay(300) // Подписываемся ещё позже
sharedFlow.collect { println("Второй подписчик получил: $it") }
}
}
StateFlow — это поток, который всегда хранит одно последнее значениЕ. Он идеально подходит для представления состояния (например, UI-состояния в MVVM).
- Всегда содержит одно актуальное значение.
- Если новое значение не отличается от текущего, оно не отправляется подписчикам.
- Новый подписчик сразу получает текущее значение.
- Можно думать о StateFlow как о LiveData, но для корутин.
import kotlinx.coroutines.*
import kotlinx.coroutines.flow.*
fun main() = runBlocking {
val stateFlow = MutableStateFlow(0) // Начальное состояние
launch {
delay(200) // Подписываемся позже
stateFlow.collect { println("Подписчик получил: $it") }
}
delay(100)
stateFlow.value = 1 // Меняем состояние
stateFlow.value = 2 // Меняем состояние
}
Ставь 👍 и забирай 📚 Базу знаний
Please open Telegram to view this post
VIEW IN TELEGRAM
👍7
Используйте Flow для управления состоянием корзины: обновляйте данные через методы emit или stateFlow, чтобы динамически отслеживать изменения. Реализуйте обработку добавления, удаления, обновления товаров через действия, которые изменяют состояние корзины.
Ставь 👍 если знал ответ, 🔥 если нет
Забирай 📚 Базу знаний
Please open Telegram to view this post
VIEW IN TELEGRAM
🔥2
Модификации могут означать разные вещи в зависимости от контекста. В 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