декабря 21, 2025
13 мин. чтения

Вопросы на собеседовании для Junior Android-разработчика

interview
career-advice
job-search
entry-level
Вопросы на собеседовании для Junior Android-разработчика
Milad Bonakdar

Milad Bonakdar

Автор

Подготовьтесь к Junior Android-собеседованию с вопросами по Kotlin, lifecycle, Jetpack Compose, Room, сети и корутинам.


Введение

На собеседовании Junior Android-разработчика обычно проверяют, можете ли вы практично объяснить Kotlin, жизненные циклы Android, состояние в Compose, локальное хранение, сетевые запросы и корутины. Сильный ответ связывает тему с небольшой надежной app: правильно хранить UI state, не блокировать главный поток, безопасно сохранять данные и понятно обрабатывать ошибки.

Используйте это руководство, чтобы отработать короткие ответы, а затем привяжите каждую тему к проекту из резюме или портфолио. Todo-приложение, погодная app или экран с API помогут звучать конкретно, а не как при пересказе заученного текста.


Основы Kotlin (6 вопросов)

1. В чем разница между val и var в Kotlin?

Ответ:

  • val: Объявляет неизменяемую (только для чтения) переменную. После присвоения ее значение нельзя изменить.
  • var: Объявляет изменяемую переменную. Ее значение можно изменить после инициализации.
  • Рекомендация: Используйте val по умолчанию для безопасности. Используйте var только тогда, когда вам нужно переназначить значение.
val name = "John"  // Не может быть изменено
var age = 25       // Может быть изменено
age = 26           // Допустимо
// name = "Jane"   // Ошибка: Val не может быть переназначена

Распространенность: Очень часто Сложность: Легко


2. Объясните Nullable типы и оператор Safe Call в Kotlin.

Ответ: Система типов Kotlin различает nullable и non-nullable типы, чтобы предотвратить исключения NullPointerException.

  • Nullable тип: Добавьте ? после типа: String?
  • Safe Call (?.): Вызывает метод, только если объект не равен null
  • Elvis Operator (?:): Предоставляет значение по умолчанию, если null
  • Not-null Assertion (!!): Выбрасывает исключение, если null (используйте умеренно)
var email: String? = "[email protected]"

// Safe call
val length = email?.length  // Возвращает null, если email равен null

// Elvis operator
val displayEmail = email ?: "No email"

// Let function
email?.let {
    println("Email: $it")
}

// Not-null assertion (опасно)
val len = email!!.length  // Выбрасывает исключение, если email равен null

Распространенность: Очень часто Сложность: Легко


3. В чем разница между class и data class в Kotlin?

Ответ:

  • Обычный класс: Стандартное определение класса
  • Data Class: Автоматически генерирует полезные методы для хранения данных
    • equals() и hashCode()
    • toString()
    • Функция copy()
    • Функции componentN() для деструктуризации
// Обычный класс
class Person(val name: String, val age: Int)

// Data class
data class User(val name: String, val age: Int)

val user1 = User("John", 25)
val user2 = User("John", 25)

println(user1 == user2)  // true (equals() сгенерирован)
println(user1)           // User(name=John, age=25) (toString() сгенерирован)

// Копирование с изменениями
val user3 = user1.copy(age = 26)

// Деструктуризация
val (name, age) = user1

Распространенность: Очень часто Сложность: Легко


4. Что такое Lambda-выражения и Higher-order функции в Kotlin?

Ответ:

  • Lambda: Анонимная функция, которая может быть передана как значение
  • Higher-order функция: Функция, которая принимает функции в качестве параметров или возвращает функцию
// Lambda-выражение
val sum = { a: Int, b: Int -> a + b }
println(sum(5, 3))  // 8

// Higher-order функция
fun calculate(a: Int, b: Int, operation: (Int, Int) -> Int): Int {
    return operation(a, b)
}

val result = calculate(10, 5) { x, y -> x * y }
println(result)  // 50

// Операции с коллекциями
val numbers = listOf(1, 2, 3, 4, 5)
val doubled = numbers.map { it * 2 }
val evens = numbers.filter { it % 2 == 0 }

println(doubled)  // [2, 4, 6, 8, 10]
println(evens)    // [2, 4]

Распространенность: Очень часто Сложность: Средняя


5. Объясните Extension Functions в Kotlin.

Ответ: Extension Functions позволяют добавлять новые функции к существующим классам без изменения их исходного кода.

// Extension function для String
fun String.isPalindrome(): Boolean {
    return this == this.reversed()
}

println("radar".isPalindrome())  // true
println("hello".isPalindrome())  // false

// Extension function с параметрами
fun Int.times(action: () -> Unit) {
    repeat(this) {
        action()
    }
}

3.times {
    println("Hello")
}
// Выводит "Hello" три раза

Распространенность: Часто Сложность: Легко


6. В чем разница между == и === в Kotlin?

Ответ:

  • ==: Структурное равенство (сравнивает значения с использованием equals())
  • ===: Ссылочное равенство (сравнивает ссылки в памяти)
val str1 = "Hello"
val str2 = "Hello"
val str3 = str1

println(str1 == str2)   // true (одинаковое значение)
println(str1 === str2)  // true (оптимизация string pool)
println(str1 === str3)  // true (одна и та же ссылка)

val list1 = listOf(1, 2, 3)
val list2 = listOf(1, 2, 3)

println(list1 == list2)   // true (одинаковое содержимое)
println(list1 === list2)  // false (разные объекты)

Распространенность: Часто Сложность: Легко


Компоненты Android (5 вопросов)

7. Что такое Activity и объясните ее жизненный цикл.

Ответ: Activity представляет собой один экран с пользовательским интерфейсом. У него есть четко определенный жизненный цикл:

Loading diagram...
  • onCreate(): Activity создается. Инициализируйте UI, установите content view.
  • onStart(): Activity становится видимой.
  • onResume(): Activity находится на переднем плане и интерактивна.
  • onPause(): Activity теряет фокус (другая activity выходит на передний план).
  • onStop(): Activity больше не видна.
  • onDestroy(): Activity уничтожается.
class MainActivity : AppCompatActivity() {
    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_main)
        // Инициализация views, настройка данных
    }
    
    override fun onStart() {
        super.onStart()
        // Activity становится видимой
    }
    
    override fun onResume() {
        super.onResume()
        // Activity интерактивна, запуск анимаций
    }
    
    override fun onPause() {
        super.onPause()
        // Activity теряет фокус, приостановка текущих действий
    }
}

Распространенность: Очень часто Сложность: Легко


8. В чем разница между Activity и Fragment?

Ответ:

  • Activity: Представляет собой полный экран. Точка входа для взаимодействия с пользователем. Имеет свой собственный жизненный цикл.
  • Fragment: Многократно используемая часть UI внутри Activity. В одной activity может существовать несколько фрагментов. Имеет свой собственный жизненный цикл, связанный с хост-activity.
  • Преимущества Fragment:
    • Возможность повторного использования в разных activity
    • Модульные компоненты UI
    • Поддержка планшетов (многопанельные макеты)
    • Интеграция компонента Navigation
class MyFragment : Fragment() {
    override fun onCreateView(
        inflater: LayoutInflater,
        container: ViewGroup?,
        savedInstanceState: Bundle?
    ): View? {
        return inflater.inflate(R.layout.fragment_my, container, false)
    }
    
    override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
        super.onViewCreated(view, savedInstanceState)
        // Инициализация views
    }
}

// В Activity
class MainActivity : AppCompatActivity() {
    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_main)
        
        supportFragmentManager.beginTransaction()
            .replace(R.id.fragment_container, MyFragment())
            .commit()
    }
}

Распространенность: Очень часто Сложность: Легко


9. Что такое Intent и какие у него типы?

Ответ: Intent - это объект обмена сообщениями, используемый для запроса действия от другого компонента приложения.

  • Explicit Intent: Указывает точный компонент для запуска (по имени класса)
  • Implicit Intent: Объявляет общее действие, и система находит подходящий компонент
// Explicit Intent - запуск конкретной activity
val intent = Intent(this, DetailActivity::class.java)
intent.putExtra("USER_ID", 123)
startActivity(intent)

// Implicit Intent - открытие URL
val webIntent = Intent(Intent.ACTION_VIEW, Uri.parse("https://example.com"))
startActivity(webIntent)

// Implicit Intent - отправка текста
val shareIntent = Intent(Intent.ACTION_SEND).apply {
    type = "text/plain"
    putExtra(Intent.EXTRA_TEXT, "Check this out!")
}
startActivity(Intent.createChooser(shareIntent, "Share via"))

// Implicit Intent - совершение телефонного звонка
val callIntent = Intent(Intent.ACTION_DIAL).apply {
    data = Uri.parse("tel:1234567890")
}
startActivity(callIntent)

Распространенность: Очень часто Сложность: Легко


10. Что такое Service в Android?

Ответ: Service - это компонент, который работает в фоновом режиме для выполнения длительных операций без пользовательского интерфейса.

  • Типы:
    • Foreground Service: Выполняет заметные операции (музыкальный проигрыватель). Отображает уведомление.
    • Background Service: Выполняет операции, не заметные напрямую пользователем.
    • Bound Service: Позволяет компонентам привязываться к нему и взаимодействовать.
class MyService : Service() {
    override fun onStartCommand(intent: Intent?, flags: Int, startId: Int): Int {
        // Выполнение фоновой работы
        Thread {
            // Длительная операция
            Thread.sleep(5000)
            stopSelf()
        }.start()
        
        return START_STICKY
    }
    
    override fun onBind(intent: Intent?): IBinder? {
        return null
    }
}

// Запуск service
val serviceIntent = Intent(this, MyService::class.java)
startService(serviceIntent)

// Остановка service
stopService(serviceIntent)

Распространенность: Часто Сложность: Средняя


11. Что такое BroadcastReceiver?

Ответ: BroadcastReceiver - это компонент, который реагирует на широковещательные объявления системы.

  • Сценарии использования: Низкий уровень заряда батареи, изменения сетевого подключения, получение SMS, завершение загрузки
  • Регистрация:
    • Статическая: В AndroidManifest.xml (ограничена в новых версиях Android)
    • Динамическая: В коде (предпочтительнее)
class MyBroadcastReceiver : BroadcastReceiver() {
    override fun onReceive(context: Context?, intent: Intent?) {
        when (intent?.action) {
            Intent.ACTION_BATTERY_LOW -> {
                // Обработка низкого уровня заряда батареи
            }
            ConnectivityManager.CONNECTIVITY_ACTION -> {
                // Обработка изменения сети
            }
        }
    }
}

// Регистрация динамически
class MainActivity : AppCompatActivity() {
    private val receiver = MyBroadcastReceiver()
    
    override fun onStart() {
        super.onStart()
        val filter = IntentFilter(Intent.ACTION_BATTERY_LOW)
        registerReceiver(receiver, filter)
    }
    
    override fun onStop() {
        super.onStop()
        unregisterReceiver(receiver)
    }
}

Распространенность: Часто Сложность: Легко


UI Development (4 вопроса)

12. В чем разница между LinearLayout, RelativeLayout и ConstraintLayout?

Ответ:

  • LinearLayout: Располагает дочерние элементы в один ряд или столбец. Простой, но может привести к вложенным макетам.
  • RelativeLayout: Располагает дочерние элементы относительно друг друга или родителя. Более гибкий, но сложный.
  • ConstraintLayout: Современный, гибкий макет. Плоская иерархия представлений. Рекомендуется для сложных UI.
<!-- ConstraintLayout example -->
<androidx.constraintlayout.widget.ConstraintLayout
    android:layout_width="match_parent"
    android:layout_height="match_parent">
    
    <TextView
        android:id="@+id/title"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="Title"
        app:layout_constraintTop_toTopOf="parent"
        app:layout_constraintStart_toStartOf="parent"
        app:layout_constraintEnd_toEndOf="parent" />
    
    <Button
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="Click Me"
        app:layout_constraintTop_toBottomOf="@id/title"
        app:layout_constraintStart_toStartOf="parent" />
</androidx.constraintlayout.widget.ConstraintLayout>

Распространенность: Очень часто Сложность: Легко


13. Что такое RecyclerView и как он работает?

Ответ: RecyclerView - это эффективный виджет для отображения больших списков путем переработки views.

  • Компоненты:
    • Adapter: Связывает данные с views
    • ViewHolder: Хранит ссылки на views (избегает вызовов findViewById)
    • LayoutManager: Располагает элементы (Linear, Grid, Staggered)
// Data class
data class User(val name: String, val email: String)

// ViewHolder
class UserViewHolder(itemView: View) : RecyclerView.ViewHolder(itemView) {
    private val nameText: TextView = itemView.findViewById(R.id.nameText)
    private val emailText: TextView = itemView.findViewById(R.id.emailText)
    
    fun bind(user: User) {
        nameText.text = user.name
        emailText.text = user.email
    }
}

// Adapter
class UserAdapter(private val users: List<User>) : 
    RecyclerView.Adapter<UserViewHolder>() {
    
    override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): UserViewHolder {
        val view = LayoutInflater.from(parent.context)
            .inflate(R.layout.item_user, parent, false)
        return UserViewHolder(view)
    }
    
    override fun onBindViewHolder(holder: UserViewHolder, position: Int) {
        holder.bind(users[position])
    }
    
    override fun getItemCount() = users.size
}

// В Activity
recyclerView.layoutManager = LinearLayoutManager(this)
recyclerView.adapter = UserAdapter(userList)

Распространенность: Очень часто Сложность: Средняя


14. Что такое Jetpack Compose?

Ответ: Jetpack Compose - это современный декларативный UI toolkit для Android.

  • Декларативный: Описывает, как должен выглядеть UI, а не как его строить
  • Преимущества: Меньше кода, интуитивно понятный, мощный, ускоряет разработку
  • Composable Functions: Строительные блоки Compose UI
@Composable
fun Greeting(name: String) {
    Text(text = "Hello, $name!")
}

@Composable
fun Counter() {
    var count by remember { mutableStateOf(0) }
    
    Column(
        modifier = Modifier.padding(16.dp),
        horizontalAlignment = Alignment.CenterHorizontally
    ) {
        Text(text = "Count: $count")
        Button(onClick = { count++ }) {
            Text("Increment")
        }
    }
}

@Preview
@Composable
fun PreviewCounter() {
    Counter()
}

Распространенность: Очень часто Сложность: Легко


15. В чем разница между match_parent и wrap_content?

Ответ: Это параметры макета, которые определяют размеры view:

  • match_parent: View расширяется, чтобы заполнить размер родителя
  • wrap_content: View устанавливает размер в соответствии со своим содержимым
  • Fixed Size: Определенное значение dp (например, 100dp)
<LinearLayout
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:orientation="vertical">
    
    <!-- Заполняет ширину родителя, устанавливает высоту по содержимому -->
    <TextView
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:text="Title" />
    
    <!-- Устанавливает размер по содержимому для обоих измерений -->
    <Button
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="Click Me" />
    
    <!-- Фиксированный размер -->
    <ImageView
        android:layout_width="100dp"
        android:layout_height="100dp"
        android:src="@drawable/icon" />
</LinearLayout>

Распространенность: Очень часто Сложность: Легко


Data & Networking (5 вопросов)

16. Как сделать сетевой запрос в Android?

Ответ: Используйте библиотеки, такие как Retrofit или OkHttp, для работы с сетью. Избегайте прямого использования HttpURLConnection.

// Retrofit setup
interface ApiService {
    @GET("users/{id}")
    suspend fun getUser(@Path("id") userId: Int): User
    
    @POST("users")
    suspend fun createUser(@Body user: User): User
}

object RetrofitClient {
    private const val BASE_URL = "https://api.example.com/"
    
    val apiService: ApiService by lazy {
        Retrofit.Builder()
            .baseUrl(BASE_URL)
            .addConverterFactory(GsonConverterFactory.create())
            .build()
            .create(ApiService::class.java)
    }
}

// Использование в ViewModel
class UserViewModel : ViewModel() {
    fun fetchUser(userId: Int) {
        viewModelScope.launch {
            try {
                val user = RetrofitClient.apiService.getUser(userId)
                // Обновление UI
            } catch (e: Exception) {
                // Обработка ошибки
            }
        }
    }
}

Распространенность: Очень часто Сложность: Средняя


17. Что такое Room и как его использовать?

Ответ: Room - это уровень абстракции над SQLite для упрощения доступа к базе данных.

  • Компоненты:
    • Entity: Представляет таблицу
    • DAO (Data Access Object): Определяет операции с базой данных
    • Database: Держатель базы данных
// Entity
@Entity(tableName = "users")
data class User(
    @PrimaryKey(autoGenerate = true) val id: Int = 0,
    @ColumnInfo(name = "name") val name: String,
    @ColumnInfo(name = "email") val email: String
)

// DAO
@Dao
interface UserDao {
    @Query("SELECT * FROM users")
    fun getAllUsers(): List<User>
    
    @Query("SELECT * FROM users WHERE id = :userId")
    fun getUserById(userId: Int): User?
    
    @Insert
    suspend fun insertUser(user: User)
    
    @Delete
    suspend fun deleteUser(user: User)
    
    @Update
    suspend fun updateUser(user: User)
}

// Database
@Database(entities = [User::class], version = 1)
abstract class AppDatabase : RoomDatabase() {
    abstract fun userDao(): UserDao
    
    companion object {
        @Volatile
        private var INSTANCE: AppDatabase? = null
        
        fun getDatabase(context: Context): AppDatabase {
            return INSTANCE ?: synchronized(this) {
                val instance = Room.databaseBuilder(
                    context.applicationContext,
                    AppDatabase::class.java,
                    "app_database"
                ).build()
                INSTANCE = instance
                instance
            }
        }
    }
}

Распространенность: Очень часто Сложность: Средняя


18. Что такое SharedPreferences?

Ответ: SharedPreferences хранит небольшие объемы примитивных данных в виде пар ключ-значение.

  • Сценарии использования: Пользовательские настройки, предпочтения, простые флаги
  • Не для: Больших данных, сложных объектов (используйте Room вместо этого)
// Сохранение данных
val sharedPref = getSharedPreferences("MyPrefs", Context.MODE_PRIVATE)
with(sharedPref.edit()) {
    putString("username", "John")
    putInt("age", 25)
    putBoolean("isLoggedIn", true)
    apply()  // или commit()
}

// Чтение данных
val username = sharedPref.getString("username", "Guest")
val age = sharedPref.getInt("age", 0)
val isLoggedIn = sharedPref.getBoolean("isLoggedIn", false)

// Удаление данных
with(sharedPref.edit()) {
    remove("username")
    apply()
}

// Очистка всего
with(sharedPref.edit()) {
    clear()
    apply()
}

Распространенность: Очень часто Сложность: Легко


19. В чем разница между apply() и commit() в SharedPreferences?

Ответ: Оба сохраняют изменения в SharedPreferences, но различаются по поведению:

  • apply(): Асинхронный. Возвращается немедленно. Изменения записываются на диск в фоновом режиме. Нет возвращаемого значения.
  • commit(): Синхронный. Блокирует, пока изменения не будут записаны. Возвращает boolean (успех/неудача).
  • Рекомендация: Используйте apply(), если вам не нужно возвращаемое значение.
val editor = sharedPref.edit()

// apply() - асинхронный, предпочтительный
editor.putString("key", "value")
editor.apply()  // Возвращается немедленно

// commit() - синхронный
editor.putString("key", "value")
val success = editor.commit()  // Ожидает записи, возвращает boolean
if (success) {
    // Сохранение выполнено успешно
}

Распространенность: Часто Сложность: Легко


20. Что такое Coroutines в Kotlin?

Ответ: Coroutines предоставляют способ написания асинхронного кода последовательно, что упрощает чтение и поддержку.

  • Преимущества: Легковесность, структурированная конкурентность, обработка исключений
  • Основные концепции:
    • suspend: Функция, которая может быть приостановлена и возобновлена
    • launch: Запускает корутину (fire and forget)
    • async: Запускает корутину и возвращает результат
    • Dispatchers: Контролируют, в каком потоке выполняется корутина
class MyViewModel : ViewModel() {
    fun loadData() {
        viewModelScope.launch {
            try {
                // Главный поток
                showLoading()
                
                // Переключение в IO поток для сетевого вызова
                val data = withContext(Dispatchers.IO) {
                    fetchDataFromNetwork()
                }
                
                // Возврат в главный поток
                updateUI(data)
            } catch (e: Exception) {
                handleError(e)
            }
        }
    }
    
    suspend fun fetchDataFromNetwork(): String {
        delay(2000)  // Имитирует задержку сети
        return "Data from server"
    }
}

// Параллельное выполнение
viewModelScope.launch {
    val deferred1 = async { fetchUser(1) }
    val deferred2 = async { fetchUser(2) }
    
    val user1 = deferred1.await()
    val user2 = deferred2.await()
}

Распространенность: Очень часто Сложность: Средняя


Newsletter subscription

Еженедельные советы по карьере, которые действительно работают

Получайте последние идеи прямо на вашу почту

Создайте резюме, которое поможет вам устроиться на 60% быстрее

За несколько минут создайте персонализированное резюме, совместимое с ATS, которое доказано увеличивает количество собеседований в 6 раз.

Создать лучшее резюме

Поделиться этим постом

Удвойте Количество Приглашений на Собеседование

Кандидаты, адаптирующие свои резюме под описание вакансии, получают в 2,5 раза больше собеседований. Используйте наш ИИ для автоматической настройки вашего резюме для каждой заявки мгновенно.