dicembre 21, 2025
14 min di lettura

Domande per il Colloquio di Sviluppatore Mobile Junior (Android): Guida Completa

interview
career-advice
job-search
entry-level
Domande per il Colloquio di Sviluppatore Mobile Junior (Android): Guida Completa
MB

Milad Bonakdar

Autore

Padroneggia i fondamenti dello sviluppo Android con domande essenziali per il colloquio che coprono Kotlin, Activity, Fragment, Jetpack Compose, persistenza dei dati e le migliori pratiche Android per sviluppatori junior.


Introduzione

Lo sviluppo Android alimenta miliardi di dispositivi in tutto il mondo, rendendola una delle piattaforme mobile più importanti. Con Kotlin come linguaggio preferito e strumenti moderni come Jetpack Compose, gli sviluppatori Android creano applicazioni ricche e performanti per diversi utenti.

Questa guida copre le domande essenziali per i colloqui per Junior Android Developer. Esploreremo i fondamenti di Kotlin, i componenti Android, lo sviluppo dell'interfaccia utente, la persistenza dei dati, il networking e le migliori pratiche per aiutarti a prepararti per il tuo primo ruolo di sviluppatore Android.


Fondamenti di Kotlin (6 Domande)

1. Qual è la differenza tra val e var in Kotlin?

Risposta:

  • val: Dichiara una variabile immutabile (di sola lettura). Una volta assegnato, il suo valore non può essere modificato.
  • var: Dichiara una variabile mutabile. Il suo valore può essere modificato dopo l'inizializzazione.
  • Best Practice: Utilizzare val di default per sicurezza. Utilizzare var solo quando è necessario riassegnare il valore.
val name = "John"  // Non può essere cambiato
var age = 25       // Può essere cambiato
age = 26           // Valido
// name = "Jane"   // Errore: Val non può essere riassegnato

Rarità: Molto Comune Difficoltà: Facile


2. Spiega i tipi Nullable e l'operatore Safe Call in Kotlin.

Risposta: Il sistema di tipi di Kotlin distingue tra tipi nullable e non-nullable per prevenire eccezioni di puntatore nullo.

  • Tipo Nullable: Aggiungi ? dopo il tipo: String?
  • Safe Call (?.): Chiama un metodo solo se l'oggetto non è null
  • Operatore Elvis (?:): Fornisce un valore di default se null
  • Not-null Assertion (!!): Lancia un'eccezione se null (usare con parsimonia)
var email: String? = "[email protected]"

// Safe call
val length = email?.length  // Restituisce null se email è null

// Operatore Elvis
val displayEmail = email ?: "Nessuna email"

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

// Not-null assertion (pericoloso)
val len = email!!.length  // Lancia un'eccezione se email è null

Rarità: Molto Comune Difficoltà: Facile


3. Qual è la differenza tra una class e una data class in Kotlin?

Risposta:

  • Regular Class: Definizione di classe standard
  • Data Class: Genera automaticamente metodi utili per contenere dati
    • equals() e hashCode()
    • toString()
    • Funzione copy()
    • Funzioni componentN() per il destructuring
// Regular class
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() generato)
println(user1)           // User(name=John, age=25) (toString() generato)

// Copy con modifiche
val user3 = user1.copy(age = 26)

// Destructuring
val (name, age) = user1

Rarità: Molto Comune Difficoltà: Facile


4. Cosa sono le espressioni Lambda e le funzioni Higher-order in Kotlin?

Risposta:

  • Lambda: Funzione anonima che può essere passata come valore
  • Higher-order Function: Funzione che accetta funzioni come parametri o restituisce una funzione
// Espressione Lambda
val sum = { a: Int, b: Int -> a + b }
println(sum(5, 3))  // 8

// Higher-order function
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

// Operazioni sulle Collection
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]

Rarità: Molto Comune Difficoltà: Media


5. Spiega le Extension Functions in Kotlin.

Risposta: Le extension functions ti permettono di aggiungere nuove funzioni a classi esistenti senza modificarne il codice sorgente.

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

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

// Extension function con parametri
fun Int.times(action: () -> Unit) {
    repeat(this) {
        action()
    }
}

3.times {
    println("Ciao")
}
// Stampa "Ciao" tre volte

Rarità: Comune Difficoltà: Facile


6. Qual è la differenza tra == e === in Kotlin?

Risposta:

  • ==: Uguaglianza strutturale (confronta i valori usando equals())
  • ===: Uguaglianza referenziale (confronta i riferimenti in memoria)
val str1 = "Ciao"
val str2 = "Ciao"
val str3 = str1

println(str1 == str2)   // true (stesso valore)
println(str1 === str2)  // true (ottimizzazione della string pool)
println(str1 === str3)  // true (stesso riferimento)

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

println(list1 == list2)   // true (stesso contenuto)
println(list1 === list2)  // false (oggetti diversi)

Rarità: Comune Difficoltà: Facile


Componenti Android (5 Domande)

7. Cosa è una Activity e spiega il suo ciclo di vita.

Risposta: Una Activity rappresenta una singola schermata con un'interfaccia utente. Ha un ciclo di vita ben definito:

Loading diagram...
  • onCreate(): L'Activity viene creata. Inizializza l'interfaccia utente, imposta la content view.
  • onStart(): L'Activity diventa visibile.
  • onResume(): L'Activity è in primo piano e interattiva.
  • onPause(): L'Activity perde il focus (un'altra activity passa in primo piano).
  • onStop(): L'Activity non è più visibile.
  • onDestroy(): L'Activity viene distrutta.
class MainActivity : AppCompatActivity() {
    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_main)
        // Inizializza le view, imposta i dati
    }
    
    override fun onStart() {
        super.onStart()
        // L'Activity diventa visibile
    }
    
    override fun onResume() {
        super.onResume()
        // L'Activity è interattiva, avvia le animazioni
    }
    
    override fun onPause() {
        super.onPause()
        // L'Activity perde il focus, mette in pausa le azioni in corso
    }
}

Rarità: Molto Comune Difficoltà: Facile


8. Qual è la differenza tra una Activity e un Fragment?

Risposta:

  • Activity: Rappresenta una schermata intera. Punto di ingresso per l'interazione dell'utente. Ha il suo ciclo di vita.
  • Fragment: Porzione riutilizzabile di interfaccia utente all'interno di una Activity. Possono esistere più fragment in una activity. Ha il suo ciclo di vita legato all'activity host.
  • Vantaggi dei Fragment:
    • Riutilizzabilità tra le activity
    • Componenti UI modulari
    • Supporto per tablet (layout multi-pannello)
    • Integrazione con il Navigation Component
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)
        // Inizializza le view
    }
}

// In 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()
    }
}

Rarità: Molto Comune Difficoltà: Facile


9. Cosa è un Intent e quali sono i suoi tipi?

Risposta: Intent è un oggetto di messaggistica utilizzato per richiedere un'azione da un altro componente dell'app.

  • Explicit Intent: Specifica l'esatto componente da avviare (tramite il nome della classe)
  • Implicit Intent: Dichiara un'azione generale e il sistema trova il componente appropriato
// Explicit Intent - avvia un'activity specifica
val intent = Intent(this, DetailActivity::class.java)
intent.putExtra("USER_ID", 123)
startActivity(intent)

// Implicit Intent - apre un URL
val webIntent = Intent(Intent.ACTION_VIEW, Uri.parse("https://esempio.com"))
startActivity(webIntent)

// Implicit Intent - condivide testo
val shareIntent = Intent(Intent.ACTION_SEND).apply {
    type = "text/plain"
    putExtra(Intent.EXTRA_TEXT, "Dai un'occhiata!")
}
startActivity(Intent.createChooser(shareIntent, "Condividi tramite"))

// Implicit Intent - effettua una chiamata telefonica
val callIntent = Intent(Intent.ACTION_DIAL).apply {
    data = Uri.parse("tel:1234567890")
}
startActivity(callIntent)

Rarità: Molto Comune Difficoltà: Facile


10. Cosa è un Service in Android?

Risposta: Un Service è un componente che viene eseguito in background per eseguire operazioni di lunga durata senza un'interfaccia utente.

  • Tipi:
    • Foreground Service: Esegue operazioni evidenti (lettore musicale). Mostra una notifica.
    • Background Service: Esegue operazioni non direttamente notate dall'utente.
    • Bound Service: Permette ai componenti di collegarsi ad esso e interagire.
class MyService : Service() {
    override fun onStartCommand(intent: Intent?, flags: Int, startId: Int): Int {
        // Esegue il lavoro in background
        Thread {
            // Operazione di lunga durata
            Thread.sleep(5000)
            stopSelf()
        }.start()
        
        return START_STICKY
    }
    
    override fun onBind(intent: Intent?): IBinder? {
        return null
    }
}

// Avvia il service
val serviceIntent = Intent(this, MyService::class.java)
startService(serviceIntent)

// Ferma il service
stopService(serviceIntent)

Rarità: Comune Difficoltà: Media


11. Cosa è un BroadcastReceiver?

Risposta: BroadcastReceiver è un componente che risponde agli annunci broadcast a livello di sistema.

  • Casi d'uso: Batteria scarica, cambiamenti di connettività di rete, SMS ricevuto, avvio completato
  • Registrazione:
    • Statica: In AndroidManifest.xml (limitata nelle versioni più recenti di Android)
    • Dinamica: Nel codice (preferita)
class MyBroadcastReceiver : BroadcastReceiver() {
    override fun onReceive(context: Context?, intent: Intent?) {
        when (intent?.action) {
            Intent.ACTION_BATTERY_LOW -> {
                // Gestisce la batteria scarica
            }
            ConnectivityManager.CONNECTIVITY_ACTION -> {
                // Gestisce il cambiamento di rete
            }
        }
    }
}

// Registra dinamicamente
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)
    }
}

Rarità: Comune Difficoltà: Facile


Sviluppo UI (4 Domande)

12. Qual è la differenza tra LinearLayout, RelativeLayout e ConstraintLayout?

Risposta:

  • LinearLayout: Dispone i figli in una singola riga o colonna. Semplice ma può portare a layout annidati.
  • RelativeLayout: Posiziona i figli rispetto agli altri o al genitore. Più flessibile ma complesso.
  • ConstraintLayout: Layout moderno e flessibile. Gerarchia di view piatta. Raccomandato per UI complesse.
<!-- Esempio di ConstraintLayout -->
<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="Titolo"
        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="Cliccami"
        app:layout_constraintTop_toBottomOf="@id/title"
        app:layout_constraintStart_toStartOf="parent" />
</androidx.constraintlayout.widget.ConstraintLayout>

Rarità: Molto Comune Difficoltà: Facile


13. Cosa è RecyclerView e come funziona?

Risposta: RecyclerView è un widget efficiente per visualizzare grandi liste riciclando le view.

  • Componenti:
    • Adapter: Collega i dati alle view
    • ViewHolder: Contiene i riferimenti alle view (evita le chiamate findViewById)
    • LayoutManager: Posiziona gli elementi (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
}

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

Rarità: Molto Comune Difficoltà: Media


14. Cosa è Jetpack Compose?

Risposta: Jetpack Compose è il toolkit UI dichiarativo moderno di Android.

  • Dichiarativo: Descrivi come dovrebbe apparire l'UI, non come costruirla
  • Vantaggi: Meno codice, intuitivo, potente, accelera lo sviluppo
  • Composable Functions: Blocchi di costruzione dell'UI di Compose
@Composable
fun Greeting(name: String) {
    Text(text = "Ciao, $name!")
}

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

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

Rarità: Molto Comune Difficoltà: Facile


15. Qual è la differenza tra match_parent e wrap_content?

Risposta: Questi sono parametri di layout che definiscono le dimensioni della view:

  • match_parent: La view si espande per riempire le dimensioni del genitore
  • wrap_content: La view si adatta alle dimensioni del suo contenuto
  • Fixed Size: Valore dp specifico (es. 100dp)
<LinearLayout
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:orientation="vertical">
    
    <!-- Riempie la larghezza del genitore, adatta l'altezza al contenuto -->
    <TextView
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:text="Titolo" />
    
    <!-- Adatta entrambe le dimensioni -->
    <Button
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="Cliccami" />
    
    <!-- Dimensione fissa -->
    <ImageView
        android:layout_width="100dp"
        android:layout_height="100dp"
        android:src="@drawable/icon" />
</LinearLayout>

Rarità: Molto Comune Difficoltà: Facile


Dati & Networking (5 Domande)

16. Come si effettua una richiesta di rete in Android?

Risposta: Utilizzare librerie come Retrofit o OkHttp per il networking. Evitare di utilizzare HttpURLConnection direttamente.

// Setup di Retrofit
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.esempio.com/"
    
    val apiService: ApiService by lazy {
        Retrofit.Builder()
            .baseUrl(BASE_URL)
            .addConverterFactory(GsonConverterFactory.create())
            .build()
            .create(ApiService::class.java)
    }
}

// Utilizzo in ViewModel
class UserViewModel : ViewModel() {
    fun fetchUser(userId: Int) {
        viewModelScope.launch {
            try {
                val user = RetrofitClient.apiService.getUser(userId)
                // Aggiorna l'UI
            } catch (e: Exception) {
                // Gestisci l'errore
            }
        }
    }
}

Rarità: Molto Comune Difficoltà: Media


17. Cosa è Room e come si usa?

Risposta: Room è un livello di astrazione sopra SQLite per un accesso al database più semplice.

  • Componenti:
    • Entity: Rappresenta una tabella
    • DAO (Data Access Object): Definisce le operazioni del database
    • Database: Contenitore del 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
            }
        }
    }
}

Rarità: Molto Comune Difficoltà: Media


18. Cosa è SharedPreferences?

Risposta: SharedPreferences memorizza piccole quantità di dati primitivi come coppie chiave-valore.

  • Casi d'uso: Impostazioni utente, preferenze, flag semplici
  • Non per: Grandi quantità di dati, oggetti complessi (utilizzare invece Room)
// Salva i dati
val sharedPref = getSharedPreferences("MyPrefs", Context.MODE_PRIVATE)
with(sharedPref.edit()) {
    putString("username", "John")
    putInt("age", 25)
    putBoolean("isLoggedIn", true)
    apply()  // o commit()
}

// Leggi i dati
val username = sharedPref.getString("username", "Ospite")
val age = sharedPref.getInt("age", 0)
val isLoggedIn = sharedPref.getBoolean("isLoggedIn", false)

// Rimuovi i dati
with(sharedPref.edit()) {
    remove("username")
    apply()
}

// Cancella tutto
with(sharedPref.edit()) {
    clear()
    apply()
}

Rarità: Molto Comune Difficoltà: Facile


19. Qual è la differenza tra apply() e commit() in SharedPreferences?

Risposta: Entrambi salvano le modifiche in SharedPreferences, ma differiscono nel comportamento:

  • apply(): Asincrono. Restituisce immediatamente. Le modifiche vengono scritte su disco in background. Nessun valore di ritorno.
  • commit(): Sincrono. Blocca fino a quando le modifiche non vengono scritte. Restituisce un booleano (successo/fallimento).
  • Best Practice: Utilizzare apply() a meno che non sia necessario il valore di ritorno.
val editor = sharedPref.edit()

// apply() - asincrono, preferito
editor.putString("key", "value")
editor.apply()  // Restituisce immediatamente

// commit() - sincrono
editor.putString("key", "value")
val success = editor.commit()  // Aspetta che la scrittura sia completata, restituisce un booleano
if (success) {
    // Salvataggio riuscito
}

Rarità: Comune Difficoltà: Facile


20. Cosa sono le Coroutine in Kotlin?

Risposta: Le coroutine forniscono un modo per scrivere codice asincrono in modo sequenziale, rendendolo più facile da leggere e mantenere.

  • Vantaggi: Leggere, concorrenza strutturata, gestione delle eccezioni
  • Concetti chiave:
    • suspend: Funzione che può essere messa in pausa e ripresa
    • launch: Avvia una coroutine (fire and forget)
    • async: Avvia una coroutine e restituisce un risultato
    • Dispatchers: Controlla su quale thread viene eseguita la coroutine
class MyViewModel : ViewModel() {
    fun loadData() {
        viewModelScope.launch {
            try {
                // Thread principale
                showLoading()
                
                // Passa al thread IO per la chiamata di rete
                val data = withContext(Dispatchers.IO) {
                    fetchDataFromNetwork()
                }
                
                // Torna al thread principale
                updateUI(data)
            } catch (e: Exception) {
                handleError(e)
            }
        }
    }
    
    suspend fun fetchDataFromNetwork(): String {
        delay(2000)  // Simula un ritardo di rete
        return "Dati dal server"
    }
}

// Esecuzione parallela
viewModelScope.launch {
    val deferred1 = async { fetchUser(1) }
    val deferred2 = async { fetchUser(2) }
    
    val user1 = deferred1.await()
    val user2 = deferred2.await()
}

Rarità: Molto Comune Difficoltà: Media


Newsletter subscription

Consigli di carriera settimanali che funzionano davvero

Ricevi le ultime idee direttamente nella tua casella di posta

Decorative doodle

Smetti di Candidarti. Inizia a Essere Assunto.

Trasforma il tuo curriculum in un magnete per colloqui con l'ottimizzazione basata sull'IA di cui si fidano i cercatori di lavoro in tutto il mondo.

Inizia gratis

Condividi questo post

Raddoppia le Tue Chiamate per Colloqui

I candidati che personalizzano il loro curriculum in base alla descrizione del lavoro ottengono 2,5 volte più colloqui. Usa la nostra IA per personalizzare automaticamente il tuo CV per ogni singola candidatura istantaneamente.

Domande per il Colloquio di Sviluppatore Mobile Junior (Android): Guida Completa | Minova - ATS Resume Builder