dezembro 21, 2025
14 min de leitura

Perguntas para Entrevista de Desenvolvedor Mobile Júnior (Android): Guia Completo

interview
career-advice
job-search
entry-level
Perguntas para Entrevista de Desenvolvedor Mobile Júnior (Android): Guia Completo
Milad Bonakdar

Milad Bonakdar

Autor

Domine os fundamentos do desenvolvimento Android com perguntas essenciais para entrevistas, abrangendo Kotlin, Activities, Fragments, Jetpack Compose, persistência de dados e as melhores práticas do Android para desenvolvedores juniores.


Introdução

O desenvolvimento Android alimenta bilhões de dispositivos em todo o mundo, tornando-o uma das plataformas móveis mais importantes. Com Kotlin como linguagem preferida e ferramentas modernas como Jetpack Compose, os desenvolvedores Android criam aplicativos ricos e de alto desempenho para diversos usuários.

Este guia aborda as principais perguntas de entrevistas para Desenvolvedores Android Júnior. Exploramos os fundamentos do Kotlin, componentes Android, desenvolvimento de UI, persistência de dados, rede e melhores práticas para ajudá-lo a se preparar para sua primeira função como desenvolvedor Android.


Fundamentos do Kotlin (6 Perguntas)

1. Qual é a diferença entre val e var em Kotlin?

Resposta:

  • val: Declara uma variável imutável (somente leitura). Uma vez atribuída, seu valor não pode ser alterado.
  • var: Declara uma variável mutável. Seu valor pode ser alterado após a inicialização.
  • Melhor Prática: Use val por padrão para segurança. Use var somente quando precisar reatribuir o valor.
val name = "John"  // Não pode ser alterado
var age = 25       // Pode ser alterado
age = 26           // Válido
// name = "Jane"   // Erro: Val não pode ser reatribuído

Raridade: Muito Comum Dificuldade: Fácil


2. Explique os tipos Nullable e o operador Safe Call em Kotlin.

Resposta: O sistema de tipos do Kotlin distingue entre tipos nullable e não nullable para evitar exceções de ponteiro nulo.

  • Tipo Nullable: Adicione ? após o tipo: String?
  • Safe Call (?.): Chama um método somente se o objeto não for nulo
  • Elvis Operator (?:): Fornece um valor padrão se for nulo
  • Not-null Assertion (!!): Lança exceção se for nulo (use com moderação)
var email: String? = "[email protected]"

// Safe call
val length = email?.length  // Retorna null se email for null

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

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

// Not-null assertion (perigoso)
val len = email!!.length  // Lança exceção se email for null

Raridade: Muito Comum Dificuldade: Fácil


3. Qual é a diferença entre uma class e uma data class em Kotlin?

Resposta:

  • Classe Regular: Definição de classe padrão
  • Data Class: Gera automaticamente métodos úteis para armazenar dados
    • equals() e hashCode()
    • toString()
    • Função copy()
    • Funções componentN() para desestruturação
// Classe regular
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() gerado)
println(user1)           // User(name=John, age=25) (toString() gerado)

// Cópia com modificações
val user3 = user1.copy(age = 26)

// Desestruturação
val (name, age) = user1

Raridade: Muito Comum Dificuldade: Fácil


4. O que são expressões Lambda e funções Higher-order em Kotlin?

Resposta:

  • Lambda: Função anônima que pode ser passada como um valor
  • Função Higher-order: Função que recebe funções como parâmetros ou retorna uma função
// Expressão Lambda
val sum = { a: Int, b: Int -> a + b }
println(sum(5, 3))  // 8

// Função 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

// Operações de coleção
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]

Raridade: Muito Comum Dificuldade: Médio


5. Explique as Extension Functions em Kotlin.

Resposta: As extension functions permitem adicionar novas funções às classes existentes sem modificar seu código-fonte.

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

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

// Extension function com parâmetros
fun Int.times(action: () -> Unit) {
    repeat(this) {
        action()
    }
}

3.times {
    println("Hello")
}
// Imprime "Hello" três vezes

Raridade: Comum Dificuldade: Fácil


6. Qual é a diferença entre == e === em Kotlin?

Resposta:

  • ==: Igualdade estrutural (compara valores usando equals())
  • ===: Igualdade referencial (compara referências de memória)
val str1 = "Hello"
val str2 = "Hello"
val str3 = str1

println(str1 == str2)   // true (mesmo valor)
println(str1 === str2)  // true (otimização do string pool)
println(str1 === str3)  // true (mesma referência)

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

println(list1 == list2)   // true (mesmo conteúdo)
println(list1 === list2)  // false (objetos diferentes)

Raridade: Comum Dificuldade: Fácil


Componentes Android (5 Perguntas)

7. O que é uma Activity e explique seu ciclo de vida.

Resposta: Uma Activity representa uma única tela com uma interface de usuário. Possui um ciclo de vida bem definido:

Loading diagram...
  • onCreate(): A Activity é criada. Inicialize a UI, defina o content view.
  • onStart(): A Activity se torna visível.
  • onResume(): A Activity está em primeiro plano e interativa.
  • onPause(): A Activity está perdendo o foco (outra activity vindo para o primeiro plano).
  • onStop(): A Activity não está mais visível.
  • onDestroy(): A Activity é destruída.
class MainActivity : AppCompatActivity() {
    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_main)
        // Inicialize as views, configure os dados
    }
    
    override fun onStart() {
        super.onStart()
        // Activity se tornando visível
    }
    
    override fun onResume() {
        super.onResume()
        // Activity é interativa, inicie animações
    }
    
    override fun onPause() {
        super.onPause()
        // Activity perdendo o foco, pause as ações em andamento
    }
}

Raridade: Muito Comum Dificuldade: Fácil


8. Qual é a diferença entre uma Activity e um Fragment?

Resposta:

  • Activity: Representa uma tela inteira. Ponto de entrada para a interação do usuário. Tem seu próprio ciclo de vida.
  • Fragment: Porção reutilizável da UI dentro de uma Activity. Vários fragments podem existir em uma activity. Tem seu próprio ciclo de vida vinculado à activity hospedeira.
  • Benefícios dos Fragments:
    • Reutilização entre activities
    • Componentes de UI modulares
    • Suporte para tablets (layouts multi-pane)
    • Integração do componente de navegação
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)
        // Inicialize as views
    }
}

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

Raridade: Muito Comum Dificuldade: Fácil


9. O que é uma Intent e quais são seus tipos?

Resposta: Intent é um objeto de mensagem usado para solicitar uma ação de outro componente do aplicativo.

  • Intent Explícita: Especifica o componente exato para iniciar (pelo nome da classe)
  • Intent Implícita: Declara uma ação geral e o sistema encontra o componente apropriado
// Intent Explícita - iniciar activity específica
val intent = Intent(this, DetailActivity::class.java)
intent.putExtra("USER_ID", 123)
startActivity(intent)

// Intent Implícita - abrir URL
val webIntent = Intent(Intent.ACTION_VIEW, Uri.parse("https://example.com"))
startActivity(webIntent)

// Intent Implícita - compartilhar texto
val shareIntent = Intent(Intent.ACTION_SEND).apply {
    type = "text/plain"
    putExtra(Intent.EXTRA_TEXT, "Confira isso!")
}
startActivity(Intent.createChooser(shareIntent, "Compartilhar via"))

// Intent Implícita - fazer chamada telefônica
val callIntent = Intent(Intent.ACTION_DIAL).apply {
    data = Uri.parse("tel:1234567890")
}
startActivity(callIntent)

Raridade: Muito Comum Dificuldade: Fácil


10. O que é um Service no Android?

Resposta: Um Service é um componente que é executado em segundo plano para executar operações de longa duração sem uma interface de usuário.

  • Tipos:
    • Foreground Service: Executa operações perceptíveis (tocador de música). Mostra notificação.
    • Background Service: Executa operações não percebidas diretamente pelo usuário.
    • Bound Service: Permite que os componentes se liguem a ele e interajam.
class MyService : Service() {
    override fun onStartCommand(intent: Intent?, flags: Int, startId: Int): Int {
        // Executar trabalho em segundo plano
        Thread {
            // Operação de longa duração
            Thread.sleep(5000)
            stopSelf()
        }.start()
        
        return START_STICKY
    }
    
    override fun onBind(intent: Intent?): IBinder? {
        return null
    }
}

// Iniciar serviço
val serviceIntent = Intent(this, MyService::class.java)
startService(serviceIntent)

// Parar serviço
stopService(serviceIntent)

Raridade: Comum Dificuldade: Médio


11. O que é um BroadcastReceiver?

Resposta: BroadcastReceiver é um componente que responde a anúncios de broadcast em todo o sistema.

  • Casos de Uso: Bateria fraca, mudanças na conectividade de rede, SMS recebido, inicialização concluída
  • Registro:
    • Estático: No AndroidManifest.xml (limitado em versões mais recentes do Android)
    • Dinâmico: No código (preferido)
class MyBroadcastReceiver : BroadcastReceiver() {
    override fun onReceive(context: Context?, intent: Intent?) {
        when (intent?.action) {
            Intent.ACTION_BATTERY_LOW -> {
                // Lidar com bateria fraca
            }
            ConnectivityManager.CONNECTIVITY_ACTION -> {
                // Lidar com mudança de rede
            }
        }
    }
}

// Registrar 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)
    }
}

Raridade: Comum Dificuldade: Fácil


Desenvolvimento de UI (4 Perguntas)

12. Qual é a diferença entre LinearLayout, RelativeLayout e ConstraintLayout?

Resposta:

  • LinearLayout: Organiza os filhos em uma única linha ou coluna. Simples, mas pode levar a layouts aninhados.
  • RelativeLayout: Posiciona os filhos em relação uns aos outros ou ao pai. Mais flexível, mas complexo.
  • ConstraintLayout: Layout moderno e flexível. Hierarquia de visualização plana. Recomendado para UIs complexas.
<!-- Exemplo de 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="Título"
        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="Clique Aqui"
        app:layout_constraintTop_toBottomOf="@id/title"
        app:layout_constraintStart_toStartOf="parent" />
</androidx.constraintlayout.widget.ConstraintLayout>

Raridade: Muito Comum Dificuldade: Fácil


13. O que é RecyclerView e como funciona?

Resposta: RecyclerView é um widget eficiente para exibir grandes listas reciclando visualizações.

  • Componentes:
    • Adapter: Vincula dados às visualizações
    • ViewHolder: Mantém referências às visualizações (evita chamadas findViewById)
    • LayoutManager: Posiciona os itens (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
}

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

Raridade: Muito Comum Dificuldade: Médio


14. O que é Jetpack Compose?

Resposta: Jetpack Compose é o moderno kit de ferramentas de UI declarativo do Android.

  • Declarativo: Descreva como a UI deve ser, não como construí-la
  • Benefícios: Menos código, intuitivo, poderoso, acelera o desenvolvimento
  • Funções Composable: Blocos de construção da UI do Compose
@Composable
fun Greeting(name: String) {
    Text(text = "Olá, $name!")
}

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

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

Raridade: Muito Comum Dificuldade: Fácil


15. Qual é a diferença entre match_parent e wrap_content?

Resposta: Esses são parâmetros de layout que definem as dimensões da visualização:

  • match_parent: A visualização se expande para preencher o tamanho do pai
  • wrap_content: A visualização se dimensiona para ajustar seu conteúdo
  • Tamanho Fixo: Valor dp específico (por exemplo, 100dp)
<LinearLayout
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:orientation="vertical">
    
    <!-- Preenche a largura do pai, envolve a altura do conteúdo -->
    <TextView
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:text="Título" />
    
    <!-- Envolve ambas as dimensões -->
    <Button
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="Clique Aqui" />
    
    <!-- Tamanho fixo -->
    <ImageView
        android:layout_width="100dp"
        android:layout_height="100dp"
        android:src="@drawable/icon" />
</LinearLayout>

Raridade: Muito Comum Dificuldade: Fácil


Dados e Rede (5 Perguntas)

16. Como você faz uma solicitação de rede no Android?

Resposta: Use bibliotecas como Retrofit ou OkHttp para rede. Evite usar HttpURLConnection diretamente.

// Configuração do 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.example.com/"
    
    val apiService: ApiService by lazy {
        Retrofit.Builder()
            .baseUrl(BASE_URL)
            .addConverterFactory(GsonConverterFactory.create())
            .build()
            .create(ApiService::class.java)
    }
}

// Uso no ViewModel
class UserViewModel : ViewModel() {
    fun fetchUser(userId: Int) {
        viewModelScope.launch {
            try {
                val user = RetrofitClient.apiService.getUser(userId)
                // Atualizar UI
            } catch (e: Exception) {
                // Lidar com erro
            }
        }
    }
}

Raridade: Muito Comum Dificuldade: Médio


17. O que é Room e como você o usa?

Resposta: Room é uma camada de abstração sobre o SQLite para facilitar o acesso ao banco de dados.

  • Componentes:
    • Entity: Representa uma tabela
    • DAO (Data Access Object): Define operações de banco de dados
    • Database: Contêiner do banco de dados
// 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
            }
        }
    }
}

Raridade: Muito Comum Dificuldade: Médio


18. O que é SharedPreferences?

Resposta: SharedPreferences armazena pequenas quantidades de dados primitivos como pares de chave-valor.

  • Casos de Uso: Configurações do usuário, preferências, flags simples
  • Não para: Grandes dados, objetos complexos (use Room em vez disso)
// Salvar dados
val sharedPref = getSharedPreferences("MyPrefs", Context.MODE_PRIVATE)
with(sharedPref.edit()) {
    putString("username", "John")
    putInt("age", 25)
    putBoolean("isLoggedIn", true)
    apply()  // ou commit()
}

// Ler dados
val username = sharedPref.getString("username", "Guest")
val age = sharedPref.getInt("age", 0)
val isLoggedIn = sharedPref.getBoolean("isLoggedIn", false)

// Remover dados
with(sharedPref.edit()) {
    remove("username")
    apply()
}

// Limpar tudo
with(sharedPref.edit()) {
    clear()
    apply()
}

Raridade: Muito Comum Dificuldade: Fácil


19. Qual é a diferença entre apply() e commit() em SharedPreferences?

Resposta: Ambos salvam as alterações no SharedPreferences, mas diferem no comportamento:

  • apply(): Assíncrono. Retorna imediatamente. Alterações gravadas no disco em segundo plano. Sem valor de retorno.
  • commit(): Síncrono. Bloqueia até que as alterações sejam gravadas. Retorna booleano (sucesso/falha).
  • Melhor Prática: Use apply() a menos que precise do valor de retorno.
val editor = sharedPref.edit()

// apply() - assíncrono, preferido
editor.putString("key", "value")
editor.apply()  // Retorna imediatamente

// commit() - síncrono
editor.putString("key", "value")
val success = editor.commit()  // Espera pela gravação, retorna booleano
if (success) {
    // Salvamento bem-sucedido
}

Raridade: Comum Dificuldade: Fácil


20. O que são Coroutines em Kotlin?

Resposta: As Coroutines fornecem uma maneira de escrever código assíncrono sequencialmente, tornando-o mais fácil de ler e manter.

  • Benefícios: Leve, concorrência estruturada, tratamento de exceções
  • Conceitos Chave:
    • suspend: Função que pode ser pausada e retomada
    • launch: Inicia uma coroutine (disparar e esquecer)
    • async: Inicia uma coroutine e retorna um resultado
    • Dispatchers: Controla em qual thread a coroutine é executada
class MyViewModel : ViewModel() {
    fun loadData() {
        viewModelScope.launch {
            try {
                // Thread principal
                showLoading()
                
                // Mudar para a thread IO para chamada de rede
                val data = withContext(Dispatchers.IO) {
                    fetchDataFromNetwork()
                }
                
                // De volta à thread principal
                updateUI(data)
            } catch (e: Exception) {
                handleError(e)
            }
        }
    }
    
    suspend fun fetchDataFromNetwork(): String {
        delay(2000)  // Simula atraso de rede
        return "Dados do servidor"
    }
}

// Execução paralela
viewModelScope.launch {
    val deferred1 = async { fetchUser(1) }
    val deferred2 = async { fetchUser(2) }
    
    val user1 = deferred1.await()
    val user2 = deferred2.await()
}

Raridade: Muito Comum Dificuldade: Médio


Newsletter subscription

Dicas de carreira semanais que realmente funcionam

Receba as últimas ideias diretamente na sua caixa de entrada

Sua Próxima Entrevista Está a Apenas um Currículo de Distância

Crie um currículo profissional e otimizado em minutos. Não são necessárias habilidades de design—apenas resultados comprovados.

Criar meu currículo

Compartilhar esta publicação

Reduza o Tempo de Escrita do Currículo em 90%

O candidato a emprego médio gasta mais de 3 horas formatando um currículo. Nossa IA faz isso em menos de 15 minutos, levando você à fase de candidatura 12 vezes mais rápido.