и посмотреть медиа
Kotlin | Вопросы собесов
и посмотреть медиа
Вопросы для Kotlin-разработчиков с ответами.
Вопросы для Kotlin-разработчиков с ответами.
AI бот для озвучки текста и клонирования голоса в Telegram. Создавай аудио с помощью нейросети быстро и просто.
Вопросы на Kotlin-собеседованиях: расширения, корутины, коллекции. С примерами кода и объяснениями для Android и backend.
🤔 В какой момент генерируется код при использовании SQLite? Код для работы с SQLite в Android не генерируется автоматически — разработчик сам пишет SQL-запросы и управляет БД. Но если используется Room (ORM для SQLite), то код генерируется на этапе компиляции с помощью Annotation Processing (kapt) или KSP. 🚩Обычный SQLite – без генерации кода Если используешь SQLiteOpenHelper, то код не генерируется, ты сам пишешь SQL-запросы: class MyDatabaseHelper(context: Context) : SQLiteOpenHelper(context, "mydb", null, 1) { override fun onCreate(db: SQLiteDatabase) { db.execSQL("CREATE TABLE users (id INTEGER PRIMARY KEY, name TEXT)") } override fun onUpgrade(db: SQLiteDatabase, oldVersion: Int, newVersion: Int) { db.execSQL("DROP TABLE IF EXISTS users") onCreate(db) } } 🚩Room – код генерируется при компиляции Если используешь Room, код автоматически генерируется во время компиляции с помощью Annotation Processing (kapt) или KSP. Ты пишешь аннотации (@Entity, @Dao, @Database). Room-аннотации анализируются при компиляции (kapt / KSP). Генерируется SQL-код и DAO-методы. @Entity data class User( @PrimaryKey val id: Int, val name: String ) @Dao interface UserDao { @Query("SELECT * FROM User") fun getAllUsers(): List @Insert fun insert(user: User) } @Database(entities = [User::class], version = 1) abstract class AppDatabase : RoomDatabase() { abstract fun userDao(): UserDao } 🚩Когда именно генерируется код Room? Если используешь kapt (Annotation Processor) или KSP, то код генерируется во время компиляции. dependencies { implementation("androidx.room:room-runtime:2.6.1") kapt("androidx.room:room-compiler:2.6.1") // Кодогенерация } Пример с KSP (быстрее kapt) dependencies { implementation("androidx.room:room-runtime:2.6.1") ksp("androidx.room:room-compiler:2.6.1") // Кодогенерация } Ставь 👍 и забирай 📚 Базу знаний
Открыть канал и посмотреть медиа🤔 Почему нельзя передавать параметры в конструктор фрагмента? Потому что Android может восстанавливать фрагменты из состояния при конфигурационных изменениях (например, при повороте экрана) через пустой конструктор. Если ты используешь собственный конструктор, параметры не сохранятся, и приложение может упасть или вести себя некорректно. Ставь 👍 если знал ответ, 🔥 если нет Забирай 📚 Базу знаний
Открыть канал и посмотреть медиа🤔 Как собираем код? Сборка Android-приложения проходит несколько этапов: Компиляция (.kt/.java → .class → .dex) Объединение ресурсов (XML, PNG → R.java) Сборка APK/AAB Подписывание и оптимизация Установка и запуск на устройстве 🚩Компиляция кода (`.kt/.java → .dex`) Компиляция Kotlin/Java в байткод JVM (.class) Kotlin-код (.kt) → Java-байткод (.class) Java-код (.java) → .class - Используются компиляторы: - kotlinc (Kotlin Compiler) - javac (Java Compiler) // Kotlin-код (MainActivity.kt) fun main() { println("Привет, Android!") } kotlinc MainActivity.kt -d MainActivity.class Преобразование .class в `.dex* Android не использует байткод JVM, а преобразует .class в Dalvik Executable (.dex). d8 MainActivity.class --output classes.dex 🚩Компиляция ресурсов (`XML, PNG → R.java → .dex`) Android Gradle Plugin (AGP) обрабатывает ресурсы - res/layout/*.xml → UI файлы - res/drawable/*.png → Иконки - AndroidManifest.xml → Метаинформация public final class R { public static final class layout { public static final int activity_main = 0x7f0a0000; } } 🚩Сборка APK/AAB APK (старый формат) и AAB (новый формат Google Play) classes.dex + res/ + AndroidManifest.xml объединяются Проходит обфускация (ProGuard / R8) APK/AAB упаковывается в ZIP-архив zipalign -v 4 app.apk signed_app.apk 🚩Подписывание и оптимизация APK/AAB должен быть подписан перед установкой apksigner sign --ks my-release-key.jks --out signed_app.apk app-release.apk Установка и запуск adb install signed_app.apk adb shell am start -n com.example.app/.MainActivity Ставь 👍 и забирай 📚 Базу знаний
Открыть канал и посмотреть медиа🤔 Что такое Doze Mode? Doze — это режим энергосбережения, введённый с Android 6.0. Когда устройство долго не используется, система ограничивает: - Доступ к сети. - WakeLock-и. - Фоновые задачи и синхронизации. Исключения: alarms, high-priority FCM, foreground service. Ставь 👍 если знал ответ, 🔥 если нет Забирай 📚 Базу знаний
Открыть канал и посмотреть медиа🤔 Что происходит когда делаешь ==? В Kotlin оператор == используется для структурного сравнения объектов. 🚩Что делает `==` в Kotlin? Оператор == вызывает метод equals(), чтобы проверить содержимое объектов, а не их ссылки. data class User(val name: String) fun main() { val user1 = User("Alice") val user2 = User("Alice") println(user1 == user2) // true (структурное сравнение) println(user1 === user2) // false (сравнение ссылок) } 🚩Чем `==` отличается от `===`? == проверяет, равны ли данные объектов (equals()). === проверяет, ссылаются ли объекты на один и тот же участок памяти. val str1 = "Hello" val str2 = "Hello" println(str1 == str2) // true (содержимое одинаковое) println(str1 === str2) // true (Kotlin кеширует строки) val obj1 = String("Hello".toCharArray()) val obj2 = String("Hello".toCharArray()) println(obj1 == obj2) // true (содержимое одинаковое) println(obj1 === obj2) // false (разные объекты в памяти) 🚩Как работает `==` для классов? Если equals() не переопределён, то сравниваются ссылки (как ===). class Person(val name: String) fun main() { val p1 = Person("Bob") val p2 = Person("Bob") println(p1 == p2) // false (equals() не переопределён, сравниваются ссылки) } Чтобы == работал по содержимому, нужно переопределить equals() class Person(val name: String) { override fun equals(other: Any?): Boolean { return other is Person && other.name == this.name } } fun main() { val p1 = Person("Bob") val p2 = Person("Bob") println(p1 == p2) // true (equals() сравнивает содержимое) } 🚩Как `==` работает с `null`? Kotlin предотвращает NullPointerException при сравнении с null: val a: String? = null val b: String? = "Hello" println(a == b) // false (без NPE) println(a == null) // true Когда a == b, на самом деле выполняется: a?.equals(b) ?: (b === null) Ставь 👍 и забирай 📚 Базу знаний
Открыть канал и посмотреть медиа🤔 Что такое примитивы? Примитивы — это базовые типы данных, которые хранят значения напрямую, а не как объекты. • Основные типы: int, float, double, boolean, char, byte, short, long. • Примитивы эффективны по памяти и скорости, но не имеют методов. Оболочки примитивов (Integer, Double и т.д.) позволяют использовать их как объекты. Ставь 👍 если знал ответ, 🔥 если нет Забирай 📚 Базу знаний
Открыть канал и посмотреть медиа🤔 Что при создании классов в Kotlin изменились по сравнению с Java? При создании классов по сравнению с Java произошли несколько значительных изменений и упрощений. Kotlin предлагает более лаконичный и выразительный синтаксис, что делает код более читаемым и удобным. 🚩Объявление классов и конструкторов В Kotlin объявление классов и их конструкторов значительно упрощено. В Java public class Person { private String name; private int age; public Person(String name, int age) { this.name = name; this.age = age; } public String getName() { return name; } public int getAge() { return age; } } В Kotlin class Person(val name: String, val age: Int) 🟠Статические члены В Java для объявления статических членов используется ключевое слово static. В Kotlin вместо этого используются companion object. В Java public class MyClass { public static final String CONSTANT = "constant"; public static void staticMethod() { // Some code } } В Kotlin class MyClass { companion object { const val CONSTANT = "constant" @JvmStatic fun staticMethod() { // Some code } } } 🟠Data классы Kotlin предоставляет специальный тип классов — data классы, которые автоматически генерируют методы equals(), hashCode(), toString(), copy(), и componentN(). В Java public class User { private String name; private int age; public User(String name, int age) { this.name = name; this.age = age; } @Override public boolean equals(Object o) { // Implementation } @Override public int hashCode() { // Implementation } @Override public String toString() { // Implementation } } В Kotlin data class User(val name: String, val age: Int) 🟠Свойства и методы доступа В Kotlin свойства объявляются напрямую, и методы доступа (геттеры и сеттеры) генерируются автоматически. В Java public class Rectangle { private int width; private int height; public int getWidth() { return width; } public void setWidth(int width) { this.width = width; } public int getHeight() { return height; } public void setHeight(int height) { this.height = height; } } В Kotlin class Rectangle(var width: Int, var height: Int) Ставь 👍 и забирай 📚 Базу знаний
Открыть канал и посмотреть медиа🤔 Зачем в сервисах нужен метод onBind()? Метод onBind() используется для организации привязки клиента к сервису. Это позволяет: - Взаимодействовать с сервисом из Activity/Fragment напрямую. - Получить объект для вызова методов сервиса. Если сервис только запускается (без привязки), onBind() может возвращать null. Ставь 👍 если знал ответ, 🔥 если нет Забирай 📚 Базу знаний
Открыть канал и посмотреть медиа🤔 Как в Ретрофите изменять все запросы? В Retrofit можно изменять все запросы глобально с помощью Interceptor (перехватчика) в OkHttp. Это позволяет добавлять или изменять заголовки, параметры запроса, авторизацию, логирование и многое другое. 🟠Изменение всех запросов с помощью `Interceptor` Перехватчик (Interceptor) позволяет модифицировать запрос перед его отправкой. class AuthInterceptor(private val tokenProvider: TokenProvider) : Interceptor { override fun intercept(chain: Interceptor.Chain): Response { val request = chain.request().newBuilder() .addHeader("Authorization", "Bearer ${tokenProvider.getToken()}") .addHeader("Accept", "application/json") .build() return chain.proceed(request) } } Добавляем перехватчик в OkHttpClient: val okHttpClient = OkHttpClient.Builder() .addInterceptor(AuthInterceptor(tokenProvider)) .build() val retrofit = Retrofit.Builder() .baseUrl("Ссылка скрыта .client(okHttpClient) .addConverterFactory(GsonConverterFactory.create()) .build() 🟠Добавление общих Query параметров Иногда нужно добавлять общие GET-параметры (например, API-ключ). class QueryInterceptor : Interceptor { override fun intercept(chain: Interceptor.Chain): Response { val originalRequest = chain.request() val originalUrl = originalRequest.url val newUrl = originalUrl.newBuilder() .addQueryParameter("api_key", "YOUR_API_KEY") .build() val newRequest = originalRequest.newBuilder() .url(newUrl) .build() return chain.proceed(newRequest) } } Добавляем в OkHttpClient: val okHttpClient = OkHttpClient.Builder() .addInterceptor(QueryInterceptor()) .build() 🟠Автоматическая повторная авторизация (Refresh Token) Если сервер возвращает 401 Unauthorized, можно обновить токен и повторить запрос. class AuthenticatorInterceptor(private val tokenProvider: TokenProvider) : Interceptor { override fun intercept(chain: Interceptor.Chain): Response { var request = chain.request() var response = chain.proceed(request) if (response.code == 401) { // Получаем новый токен val newToken = tokenProvider.refreshToken() // Делаем новый запрос с обновлённым токеном val newRequest = request.newBuilder() .header("Authorization", "Bearer $newToken") .build() response.close() // Закрываем старый ответ response = chain.proceed(newRequest) // Повторяем запрос } return response } } Добавляем в OkHttpClient: val okHttpClient = OkHttpClient.Builder() .addInterceptor(AuthenticatorInterceptor(tokenProvider)) .build() 🟠Логирование всех запросов Для отладки удобно логировать все запросы и ответы. val loggingInterceptor = HttpLoggingInterceptor().apply { level = HttpLoggingInterceptor.Level.BODY } val okHttpClient = OkHttpClient.Builder() .addInterceptor(loggingInterceptor) .build() 🟠Полностью менять `baseUrl` (динамический URL) Если в приложении нужно менять baseUrl, можно изменять его перед каждым запросом. class BaseUrlInterceptor(private val urlProvider: UrlProvider) : Interceptor { override fun intercept(chain: Interceptor.Chain): Response { val originalRequest = chain.request() val newUrl = urlProvider.getBaseUrl() + originalRequest.url.encodedPath val newRequest = originalRequest.newBuilder() .url(newUrl) .build() return chain.proceed(newRequest) } } Используем в OkHttpClient: val okHttpClient = OkHttpClient.Builder() .addInterceptor(BaseUrlInterceptor(urlProvider)) .build() Ставь 👍 и забирай 📚 Базу знаний
Открыть канал и посмотреть медиаТолько зарегистрированные пользователи могут делиться своим мнением.
Станьте первым, кто поделится своим впечатлением об этом ресурсе!