В Kotlin можно добавлять свойства-расширения (
extension properties), но только с кастомным get (геттером). Расширяемые свойства могут быть только вычисляемыми (
val), потому что нельзя создать field внутри расширения. val String.firstChar: Char
get() = this[0]
fun main() {
println("Kotlin".firstChar) // K
}
Для
var нужно и get(), и set(), но всё равно нельзя использовать field. var StringBuilder.lastChar: Char
get() = this[length - 1]
set(value) {
this.setCharAt(length - 1, value)
}
fun main() {
val sb = StringBuilder("Hello")
println(sb.lastChar) // o
sb.lastChar = '!'
println(sb) // Hell!
}
Такой код НЕ скомпилируется!
var String.someProperty: String = "Default" // Ошибка!
Ставь 👍 и забирай 📚 Базу знаний
Please open Telegram to view this post
VIEW IN TELEGRAM
👍2
Все классы в Java неявно наследуются от класса Object, который находится в пакете java.lang.
Ставь 👍 если знал ответ, 🔥 если нет
Забирай 📚 Базу знаний
Please open Telegram to view this post
VIEW IN TELEGRAM
🔥1
Ключевое слово
object в Kotlin имеет несколько важных применений, и оно является одной из наиболее мощных и уникальных возможностей языка. Kotlin предоставляет встроенную поддержку для создания singleton-объектов. Это объект, который имеет единственный экземпляр в приложении.
object Database {
val name = "MainDatabase"
fun connect() {
println("Подключение к базе данных $name")
}
}
fun main() {
Database.connect() // Подключение к базе данных MainDatabase
}Ключевое слово
object может использоваться для создания анонимных объектов (объектов без имени). Это полезно, если нужно создать временный объект или реализовать интерфейс/абстрактный класс.fun main() {
val listener = object : ClickListener {
override fun onClick() {
println("Кнопка нажата")
}
}
listener.onClick()
}
interface ClickListener {
fun onClick()
}Ключевое слово
object можно использовать внутри класса для объявления компаньон-объекта. Это позволяет создавать статические методы и переменные в классе.class User(val name: String) {
companion object {
fun createGuest() = User("Guest")
}
}
fun main() {
val guest = User.createGuest()
println(guest.name) // Guest
}Ключевое слово
object может использоваться для объявления объектов в коде прямо "на месте".val myObject = object {
val x = 10
fun printX() {
println(x)
}
}
fun main() {
myObject.printX() // 10
}Вместо написания множества шаблонного кода для Singleton, анонимных объектов или статических методов, вы получаете готовую реализацию из коробки.
В случае
object, компилятор Kotlin автоматически гарантирует, что объект создаётся в потокобезопасном режиме.object можно использовать практически везде: глобально, локально, внутри классов и функций.Ставь 👍 и забирай 📚 Базу знаний
Please open Telegram to view this post
VIEW IN TELEGRAM
👍3
- Bubble API (мессенджеры).
- Жесткое ограничение на фоновые доступы к геолокации.
- One-time permissions.
- Уточнение доступа к клипборду.
- Запрет на несанкционированный доступ к камере/микрофону в фоне.
Ставь 👍 если знал ответ, 🔥 если нет
Забирай 📚 Базу знаний
Please open Telegram to view this post
VIEW IN TELEGRAM
🔥5💊1
Map – это коллекция пар ключ-значение. Каждый ключ уникален, а значения могут повторяться. В Kotlin Map не наследуется от Collection, но является частью стандартных коллекций.В Kotlin есть два основных типа
Map: Map (неизменяемая) – нельзя добавлять/удалять элементы после создания. MutableMap (изменяемая) – можно добавлять, удалять и изменять элементы. Создаётся с помощью
mapOf()val users = mapOf(1 to "Alice", 2 to "Bob", 3 to "Charlie")
println(users[1]) // Выведет: Alice
Создаётся с помощью
mutableMapOf()val users = mutableMapOf(1 to "Alice", 2 to "Bob")
users[3] = "Charlie" // Добавляем элемент
users[1] = "Alex" // Изменяем значение по ключу
users.remove(2) // Удаляем элемент
println(users) // {1=Alex, 3=Charlie}
map[key] – получить значение (или null, если ключа нет). map.getValue(key) – получить значение (или исключение, если ключа нет). map.getOrDefault(key, defaultValue) – вернуть значение или defaultValue, если ключа нет. map.getOrElse(key) { default } – если ключа нет, выполнить лямбда-выражение. val users = mapOf(1 to "Alice", 2 to "Bob")
println(users[1]) // Alice
println(users.getOrDefault(3, "Unknown")) // Unknown
map.containsKey(key) – есть ли ключ? map.containsValue(value) – есть ли значение? println(users.containsKey(2)) // true
println(users.containsValue("Charlie")) // false
Перебор элементов
for ((key, value) in users) {
println("ID: $key, Name: $value")
}Фильтрация
Mapval filtered = users.filter { (key, value) -> key % 2 == 0 }
println(filtered) // {2=Bob}mapOf() – не гарантирует порядок. linkedMapOf() – сохраняет порядок добавления. Обычный
HashMap (mutableMapOf()) – O(1) для поиска по ключу. TreeMap – O(log n), но поддерживает сортировку по ключам. val sortedUsers = sortedMapOf(3 to "Charlie", 1 to "Alice", 2 to "Bob")
println(sortedUsers) // {1=Alice, 2=Bob, 3=Charlie}
Ставь 👍 и забирай 📚 Базу знаний
Please open Telegram to view this post
VIEW IN TELEGRAM
👍4🔥1
2. Байткод преобразуется в DEX-файл (classes.dex).
3. Собираются ресурсы (aapt, aapt2).
4. Всё упаковывается в .apk.
5. Приложение подписывается ключом (debug/release).
Ставь 👍 если знал ответ, 🔥 если нет
Забирай 📚 Базу знаний
Please open Telegram to view this post
VIEW IN TELEGRAM
🔥6👍2
Различия между Android 7 (Nougat) и Android 8 (Oreo) заключаются в добавленных функциях, изменениях в производительности, безопасности, работе приложений и пользовательском интерфейсе.
Android 7 (Nougat):
Впервые представлена технология Doze on the Go, которая снижает энергопотребление приложений, когда устройство неактивно.
Улучшена многозадачность благодаря Split-Screen Mode (режим разделения экрана).
Android 8 (Oreo):
Введена система Vitals, которая отслеживает поведение приложений и оптимизирует их производительность, снижая потребление батареи и ресурсов.
Фоновое ограничение (Background Limits): приложения, работающие в фоновом режиме, имеют жёсткие ограничения на использование ресурсов (например, CPU и батареи).
Android 7 (Nougat):
Режим разделения экрана (Split-Screen): позволяет одновременно запускать два приложения. Быстрая смена между последними приложениями через двойное нажатие кнопки недавних задач.
Android 8 (Oreo):
Картинка в картинке (Picture-in-Picture): возможность сворачивать видео или навигационные приложения в маленькое окно, которое остается поверх других приложений.
Уведомления стали более функциональными: появились каналы уведомлений (Notification Channels), позволяющие группировать и настраивать уведомления от приложений.
Уведомления с задержкой: появилось возможность откладывать уведомления на некоторое время (Snooze).
Android 7 (Nougat):
Улучшения в системе ART (Android Runtime) позволили ускорить запуск приложений по сравнению с предыдущими версиями.
Android 8 (Oreo):
Добавлена функция Instant Apps: позволяет использовать приложения без их предварительной установки.
Приложения запускаются быстрее благодаря оптимизациям ART и сокращению кода, который нужно интерпретировать при старте.
Android 7 (Nougat):
Впервые введена функция Direct Boot, позволяющая приложениям выполнять задачи (например, будильник или приём SMS) до ввода PIN-кода.
Android 8 (Oreo):
Представлен Google Play Protect — система защиты, которая сканирует приложения на наличие вредоносного кода.
Улучшена безопасность установки приложений из сторонних источников: теперь каждое приложение требует отдельного разрешения на установку.
Укрепление работы шифрования.
Android 7 (Nougat): Поддержка новых API для работы с графикой, таких как Vulkan API для улучшения производительности в играх.
Android 8 (Oreo):
Новый формат LDAC для передачи высококачественного звука через Bluetooth (например, для беспроводных наушников).
Поддержка Wide Color Gamut для улучшения отображения цветов на экранах с расширенным динамическим диапазоном (HDR).
Android 7 (Nougat):
Уведомления стали интерактивными, добавлена возможность ответа прямо из уведомления.
Поддержка группировки уведомлений.
Android 8 (Oreo):
Каналы уведомлений: теперь можно настроить типы уведомлений, которые вы хотите получать от приложения (например, отключить уведомления о рекламных акциях, оставив только важные).
Добавлена возможность временного откладывания уведомлений (Snooze).
Android 7 (Nougat):
Поддержка многоязычия: возможность выбрать несколько языков одновременно.
Android 8 (Oreo):
Автоматическое заполнение форм (Autofill): помогает автоматически заполнять пароли и другую информацию в приложениях.
Обои адаптируются под светлую или тёмную тему интерфейса.
Ставь 👍 и забирай 📚 Базу знаний
Please open Telegram to view this post
VIEW IN TELEGRAM
👍2💊1
- action — описывает действие, которое должен выполнить Intent (например, VIEW, EDIT).
- category — определяет тип компонентов, которые могут обработать Intent (например, LAUNCHER, DEFAULT).
Ставь 👍 если знал ответ, 🔥 если нет
Забирай 📚 Базу знаний
Please open Telegram to view this post
VIEW IN TELEGRAM
🔥4
Да, объём стека изменится, а вот объём кучи останется неизменным (но нагрузка на неё увеличится).
Стек (Stack) — это область памяти для локальных переменных и вызовов функций.
- У каждого потока (Thread) есть свой отдельный стек.
- Размер стека фиксирован и устанавливается при создании потока.
- Чем больше потоков, тем больше памяти выделяется под стеки.
Если размер стека 1 МБ, и мы создаём 100 потоков, то под стеки уйдёт 100 МБ памяти.
Куча (Heap) — это область памяти для объектов.
- Куча общая для всех потоков.
- Новый поток не создаёт отдельную кучу, он использует ту же самую.
- Но больше потоков → больше создаваемых объектов → больше нагрузка на сборщик мусора (GC).
Вывод: Объём кучи не меняется автоматически, но может быстрее заполняться.
Ставь 👍 и забирай 📚 Базу знаний
Please open Telegram to view this post
VIEW IN TELEGRAM
👍3🔥1
Основные методы:
- toString() — строковое представление объекта,
- equals(Object obj) — сравнение объектов,
- hashCode() — хэш-код,
- getClass() — класс объекта,
- clone() — клонирование,
- finalize() — вызывается перед сборкой мусора,
- wait(), notify(), notifyAll() — управление потоками.
Ставь 👍 если знал ответ, 🔥 если нет
Забирай 📚 Базу знаний
Please open Telegram to view this post
VIEW IN TELEGRAM
🔥4
В Kotlin инициализаторы используются для выполнения кода при создании экземпляра класса.
Первичный (primary) конструктор
Вторичные (secondary) конструкторы
Инициализационный блок (
init) Это основной способ инициализации класса в Kotlin. Он объявляется в заголовке класса.
class User(val name: String, val age: Int)
Если нужно выполнить дополнительную логику во время создания объекта, используют блок
init: class User(val name: String, val age: Int) {
init {
println("Создан пользователь: $name, возраст: $age")
}
}Они объявляются с помощью
constructor и нужны, если:Нужно несколько способов создания объекта.
Надо вызвать другой конструктор (
this(...)). class User {
var name: String
var age: Int
constructor(name: String) {
this.name = name
this.age = 18 // Значение по умолчанию
}
constructor(name: String, age: Int) {
this.name = name
this.age = age
}
}Можно создать объект так
val user1 = User("Алекс") // возраст будет 18
val user2 = User("Иван", 25) Если есть первичный конструктор, вторичный должен его вызывать через
this(...)class User(val name: String, val age: Int) {
constructor(name: String) : this(name, 18)
}init выполняется всегда при вызове первичного конструктора. Вторичный конструктор создаёт альтернативный способ создания объекта.
class User(val name: String, val age: Int) {
init {
println("Создан пользователь: $name, возраст: $age")
}
constructor(name: String) : this(name, 18) {
println("Вызван вторичный конструктор")
}
}Ставь 👍 и забирай 📚 Базу знаний
Please open Telegram to view this post
VIEW IN TELEGRAM
👍2
- Компилируемый, статический DI.
- Высокая производительность.
- Требует больше шаблонного кода (аннотации, модули).
- Лучше подходит для крупных, долгоживущих проектов.
- Koin:
- Основан на DSL и рефлексии.
- Легче и быстрее в настройке.
- Менее производителен на старте.
- Отличен для MVP/прототипов и небольших проектов.
Ставь 👍 если знал ответ, 🔥 если нет
Забирай 📚 Базу знаний
Please open Telegram to view this post
VIEW IN TELEGRAM
💊2🔥1
Модификаторы доступа (Access Modifiers) — это ключевые слова, которые определяют, кто может видеть и использовать класс, переменную или метод.
Они помогают инкапсулировать данные и защищать код от неправильного использования.
Пример Java
public class Example {
private int a = 10; // ❌ Только внутри класса
int b = 20; // ✅ Видно внутри пакета (package-private)
protected int c = 30; // ✅ Видно в пакете и наследниках
public int d = 40; // ✅ Доступно везде
}В Kotlin есть почти такие же модификаторы, но
package-private заменён на internal.Пример Kotlin
class Example {
private val a = 10 // ❌ Только в этом классе
internal val b = 20 // ✅ Видно в модуле
protected val c = 30 // ✅ Видно в наследниках
public val d = 40 // ✅ Видно везде (по умолчанию)
}Для полей (переменных класса)
public class User {
private String name; // ❌ Скрыто от других классов
public User(String name) {
this.name = name;
}
public String getName() { // ✅ Доступ через метод
return name;
}
}Для методов
class Animal {
protected void makeSound() { // ✅ Доступен только в наследниках
System.out.println("Животное издаёт звук");
}
}
class Dog extends Animal {
public void bark() {
makeSound(); // ✅ Разрешено, потому что `protected`
System.out.println("Гав-гав!");
}
}Для классов
public class Car { } // ✅ Доступен везде
class Engine { } // ❌ Только в этом пакетеВ Kotlin можно делать
private class, но только внутри другого класса. class Car {
private class Engine // ❌ Только в этом классе
}Ставь 👍 и забирай 📚 Базу знаний
Please open Telegram to view this post
VIEW IN TELEGRAM
Ставь 👍 если знал ответ, 🔥 если нет
Забирай 📚 Базу знаний
Please open Telegram to view this post
VIEW IN TELEGRAM
🔥1
Да, Android Framework активно использует паттерн Factory в различных API. Один из самых известных примеров —
LayoutInflater. В Android для создания (инстанцирования) UI-компонентов из XML используется
LayoutInflater, который реализует паттерн Factory Method. Вместо того чтобы вручную создавать объекты View, система предоставляет фабричный метод inflate(), который "производит" экземпляры View. В XML описан интерфейс.
LayoutInflater загружает XML и создает соответствующие объекты View.Это абстрагирует создание UI-компонентов от разработчика.
val inflater = LayoutInflater.from(context)
val view = inflater.inflate(R.layout.custom_layout, parent, false)
Вместо
MediaPlayer() напрямую используется MediaPlayer.create(context, R.raw.sound), который автоматически создаёт и настраивает объект.Позволяет получить
SharedPreferences без необходимости вручную создавать экземпляр.Фабричный метод для создания
Fragment без явного вызова конструктора.Ставь 👍 и забирай 📚 Базу знаний
Please open Telegram to view this post
VIEW IN TELEGRAM
👍2
MV* паттерны — это архитектурные подходы, разделяющие логику приложения на слои:
- MVC (Model-View-Controller): Контроллер управляет моделью и обновляет представление.
- MVP (Model-View-Presenter): Презентер принимает действия от view, взаимодействует с моделью и обновляет UI.
- MVVM (Model-View-ViewModel): ViewModel содержит логику и состояние, а view автоматически подписана на изменения через биндинг.
Цель — отделить UI от логики и улучшить масштабируемость, читаемость и тестируемость.
Ставь 👍 если знал ответ, 🔥 если нет
Забирай 📚 Базу знаний
Please open Telegram to view this post
VIEW IN TELEGRAM
🔥2
ViewModel и onSaveInstanceState служат для сохранения данных при изменении конфигурации активности или фрагмента (например, при повороте экрана). Однако они решают эту задачу по-разному и имеют разные области применения. ViewModel используется для хранения и управления данными, связанных с UI, таким образом, чтобы они сохранялись при изменении конфигурации (например, при повороте экрана). Когда система уничтожает и пересоздаёт
Activity или Fragment, ViewModel остаётся в памяти до полного уничтожения владельца (например, выхода из Activity). class MyViewModel : ViewModel() {
var counter: Int = 0 // Переменная, которая сохраняется при повороте экрана
}Использование в
Activityclass MainActivity : AppCompatActivity() {
private lateinit var viewModel: MyViewModel
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
viewModel = ViewModelProvider(this).get(MyViewModel::class.java)
// Теперь viewModel.counter сохранится при повороте экрана
}
}до полного уничтожения
Activity или Fragment. списки, модели, API-данные
улучшая архитектуру.
например, при закрытии приложения
Метод
onSaveInstanceState() используется для сохранения данных в Bundle, который система автоматически передаёт при пересоздании Activity или Fragment. Когда
Activity уничтожается (например, при повороте экрана), система вызывает onSaveInstanceState(), в котором можно сохранить небольшие данные (строки, числа и т. д.). После пересоздания Activity эти данные можно восстановить из savedInstanceState. class MainActivity : AppCompatActivity() {
private var counter: Int = 0 // Значение, которое мы хотим сохранить
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
// Восстанавливаем данные, если они есть
counter = savedInstanceState?.getInt("counter_key") ?: 0
}
override fun onSaveInstanceState(outState: Bundle) {
super.onSaveInstanceState(outState)
outState.putInt("counter_key", counter) // Сохраняем значение перед уничтожением Activity
}
}EditText). BundleСтавь 👍 и забирай 📚 Базу знаний
Please open Telegram to view this post
VIEW IN TELEGRAM
👍2
Производительность измеряется в миллисекундах времени отрисовки (measure, layout, draw). Также учитывается количество операций пересчёта и перекомпоновки. В Jetpack Compose оценивается количеством recomposition и snapshot изменений.
Ставь 👍 если знал ответ, 🔥 если нет
Забирай 📚 Базу знаний
Please open Telegram to view this post
VIEW IN TELEGRAM
🔥4
В Java есть 4 модификатора доступа, которые контролируют видимость полей, методов и классов:
Поля почти всегда должны быть
private, чтобы инкапсулировать данные. Методы тоже лучше делать private, если они не должны использоваться извне. public class User {
private String name; // ✅ Доступен только внутри класса
public User(String name) {
this.name = name;
}
private void logUserAction() { // ✅ Только внутри класса
System.out.println(name + " совершил действие");
}
}Используется, если класс не должен быть доступен за пределами пакета. Полезно для вспомогательных классов.
class FileHelper { // ✅ Доступен только в этом пакете
static void readFile(String path) {
System.out.println("Читаем файл: " + path);
}
}protected лучше использовать только в abstract классах и для методов, которые должны быть переопределены. Не используй protected для полей → нарушает инкапсуляцию! abstract class Animal {
protected void makeSound() { // ✅ Наследники могут переопределять
System.out.println("Какой-то звук");
}
}
class Dog extends Animal {
@Override
protected void makeSound() {
System.out.println("Гав-гав!");
}
}Класс можно делать
public, только если он должен быть доступен во всех пакетах. Не делай поля public → нарушает инкапсуляцию! public class UserManager { // ✅ Доступен везде
public void createUser() { // ✅ Можно вызывать в любом месте
System.out.println("Создание пользователя...");
}
}final class → класс нельзя наследовать. final method → метод нельзя переопределить. final field → переменная неизменяема (константа). public final class MathUtils {
public static final double PI = 3.14159;
}Ставь 👍 и забирай 📚 Базу знаний
Please open Telegram to view this post
VIEW IN TELEGRAM
👍1
Когда выполнение suspend-функции приостанавливается (например, при delay или await), состояние функции сохраняется в continuation-объекте, а текущий поток освобождается.
Позже выполнение возобновляется с этого же места — как будто ничего не происходило. Это реализовано через стейт-машину и трансформацию кода компилятором Kotlin.
Ставь 👍 если знал ответ, 🔥 если нет
Забирай 📚 Базу знаний
Please open Telegram to view this post
VIEW IN TELEGRAM
🔥4👍1