Yazılım

Android (Kotlin) Mülakat Soruları ve Yanıtları: Mobil Geliştirici Hazırlık Rehberi

Talha AslanTalha Aslan 16 dk okuma

Android mülakat soruları, mobil geliştirici adaylarının Kotlin dil bilgisini, Jetpack Compose ile arayüz kurma becerisini ve Android bileşenlerinin yaşam döngüsünü ne kadar iyi anladığını ölçen soru setidir. 2012'den beri dijital projeler yönetiyorum ve mobil ekiplere geliştirici alırken bu soruları masanın öbür tarafından soruyorum. Bu rehberde soruları konulara göre topluyor, yanıtlarını ve kısa kod örneklerini paylaşıyorum.

Amacım size ezber listesi vermek değil. Her sorunun altında mülakatçının aslında neyi ölçtüğünü de anlatıyorum, çünkü iyi bir yanıt tanımı tekrar etmekten çok nedenini açıklar. Yazılımla ilgili diğer içeriklere yazılım kategorisinden ulaşabilirsiniz.

Android mülakat soruları nelerdir ve hangi konuları kapsar?

Android mülakat soruları dört ana başlığı kapsar: Kotlin dil temelleri, coroutine ve Flow ile eşzamanlılık, Jetpack Compose ile arayüz ve Android bileşenleri ile mimari. Hazırlanırken her başlıktan birkaç soruyu kendi cümlelerinizle yanıtlamalı, küçük bir kod yazmalı ve bu kodun neden çalıştığını sesli anlatabilmelisiniz.

Kotlin'in ağırlığını anlamak için resmi kaynağa bakalım. Android Developers Kotlin-first sayfasına göre Google, Android geliştirmenin Kotlin öncelikli olacağını Google I/O 2019'da duyurdu. Aynı sayfa, Google'ın 70'ten fazla uygulamasının Kotlin ile geliştirildiğini ve Kotlin kodu içeren uygulamaların çökme olasılığının yüzde 20 daha düşük olduğunu belirtiyor. Dolayısıyla güncel ilanların neredeyse tamamı Java yerine Kotlin bilgisini ölçüyor.

Benim önerim şu sıralama: önce Kotlin, sonra coroutine, ardından Compose, en son mimari. Dil temeli zayıf olan aday, Compose sorularında da güçlük çekiyor; çünkü lambda, extension fonksiyon ve değişmezlik mantığını bilmeden recomposition davranışını açıklamak çok zor.

Android teknik mülakat süreci hangi aşamalardan oluşur?

Şirketten şirkete değişse de sahada gördüğüm akış genelde benzer. Aşağıdaki tablo her aşamada neyin ölçüldüğünü ve nasıl hazırlanabileceğinizi özetliyor. Süreler saha tecrübesine dayalı başlangıç aralığıdır, garanti değildir.

AşamaNe ölçer?Nasıl hazırlanırsınız?Tipik süre
Ön görüşmeİletişim, deneyim, beklentiYayındaki uygulamanızı iki dakikada anlatın20-30 dk
Kavram sorularıKotlin ve Android temelleriBu yazıdaki soruları sesli yanıtlayın45-60 dk
Canlı kodlamaProblem çözme, okunabilir kodZamanlayıcıyla küçük Compose ekranları yazın45-90 dk
Ev ödeviMimari, test, proje düzeniTemiz bir örnek projeyi GitHub'da hazır tutun1-3 gün
Sistem tasarımıÇevrimdışı çalışma, senkronizasyon, ölçekBir uygulamanın veri katmanını çizerek anlatın45-60 dk

Ayrıca kıdemli pozisyonlarda davranışsal görüşme de eklenir. Orada geçmişte yaşadığınız bir üretim hatasını ve nasıl çözdüğünüzü somut anlatmanızı ister.

Kotlin'de val ile var arasındaki fark nedir?

val yalnızca bir kez atanabilen salt okunur bir referans tanımlar, var ise yeniden atanabilir. Ancak mülakatçının asıl beklediği ayrıntı şudur: val referansı sabitler, nesnenin içini değil. Örneğin val ile tanımladığınız bir MutableList'e hâlâ eleman ekleyebilirsiniz.

val liste = mutableListOf(1, 2)
liste.add(3)      // çalışır
// liste = mutableListOf() // derleme hatası

İyi bir yanıt, ekiplerin varsayılan olarak val kullandığını ve var'ı yalnızca gerçekten değişen durumlar için ayırdığını da ekler. Böylece kod okunurken hangi değerin değişebileceği hemen görürsünüz.

const val ile val farkı nedir?

const val derleme zamanında bilinen ilkel bir değer veya String içindir ve yalnızca üst seviyede, object ya da companion object içinde tanımlanabilir. Normal val ise çalışma zamanında hesaplanabilir. Bu nedenle bir fonksiyon sonucunu const val'e atayamazsınız.

Kotlin null güvenliği nasıl çalışır?

Kotlin tür sisteminde null alabilen ve alamayan türler ayrıdır. String null alamaz, String? alabilir. Derleyici, null alabilen bir değeri kontrol etmeden kullanmanıza izin vermez; böylece NullPointerException hatalarının büyük kısmını derleme aşamasında yakalarsınız.

Mülakatta sık gelen operatörleri şöyle özetleyebilirsiniz:

  • ?. güvenli çağrı: nesne null ise ifade null döner.
  • ?: Elvis operatörü: sol taraf null ise sağdaki değeri kullanır.
  • !! null olmadığını iddia eder; null çıkarsa istisna fırlatır.
  • let ile birlikte ?. kullanımı, yalnızca değer varken bir blok çalıştırır.

Kısacası !! kullanımını savunmak yerine neden kaçındığınızı anlatmanız sizi öne çıkarır. Üstelik Java kodundan gelen platform türlerinin null güvenliğini bozabileceğini söylemek, deneyimli olduğunuzu gösterir.

data class, sealed class ve object ne işe yarar?

data class, veri taşıyan sınıflar için equals, hashCode, toString, copy ve componentN fonksiyonlarını otomatik üretir. Özellikle arayüz durumunu temsil eden sınıflarda copy fonksiyonu sayesinde değişmez güncelleme yaparsınız.

sealed class ise alt sınıfları sınırlı bir hiyerarşi tanımlar. Örneğin bir ekranın Yükleniyor, Başarılı ve Hata durumlarını sealed interface ile modellerseniz, when ifadesi tüm durumları ele aldığınızı derleme zamanında kontrol eder.

sealed interface UiState {
    data object Loading : UiState
    data class Success(val items: List<String>) : UiState
    data class Error(val message: String) : UiState
}

object anahtar kelimesi tekil nesne (singleton) oluşturur. companion object ise bir sınıfa bağlı statik benzeri üyeler sağlar. Öte yandan mülakatçı genelde enum ile sealed arasındaki farkı da sorar: enum sabitleri tek örneklidir, sealed alt sınıfları ise farklı veri taşıyabilir.

Extension fonksiyon ve scope fonksiyonları nasıl kullanırsınız?

Extension fonksiyon, bir sınıfı değiştirmeden ona yeni bir fonksiyon eklemiş gibi yazmanızı sağlar. Arka planda statik bir fonksiyona dönüşür; yani sınıfın private üyelerine erişemez ve çok biçimli davranmaz. Mülakatçılar bu ayrıntıyı sık soruyor.

Scope fonksiyonlarda ise fark iki eksende ortaya çıkar: nesneye it mi this ile mi eriştiğiniz ve fonksiyonun ne döndürdüğü. Aşağıdaki özet işinizi kolaylaştırır:

  • let: it ile erişir, lambda sonucunu döndürür; null kontrolünde sık kullanılır.
  • run: this ile erişir, lambda sonucunu döndürür.
  • apply: this ile erişir, nesnenin kendisini döndürür; yapılandırma için uygundur.
  • also: it ile erişir, nesnenin kendisini döndürür; loglama gibi yan etkiler için uygundur.
  • with: extension değildir, nesneyi parametre olarak alır.

Yine de en iyi yanıt, bu fonksiyonları iç içe fazla kullanmanın okunabilirliği bozduğunu kabul eden yanıttır.

Coroutine nedir ve thread'den farkı nedir?

Coroutine, askıya alınabilen hafif bir hesaplama birimidir. Bir thread bloklandığında o işletim sistemi thread'i boşta bekler; coroutine ise suspend noktasında askıya alınır ve thread başka işler için serbest kalır. Bu yüzden binlerce coroutine'i az sayıda thread üzerinde çalıştırabilirsiniz.

Mülakatta mutlaka dispatcher sorusu gelir. Dispatchers.Main arayüz işleri, Dispatchers.IO ağ ve disk gibi bekleme ağırlıklı işler, Dispatchers.Default ise işlemci yoğun hesaplamalar içindir. Örneğin bir JSON listesini sıralamak Default, veritabanından okumak IO işidir.

viewModelScope.launch {
    val kullanicilar = withContext(Dispatchers.IO) {
        repository.getirKullanicilar()
    }
    _state.value = UiState.Success(kullanicilar)
}

Ayrıca launch ile async farkını bilmelisiniz: launch sonuç döndürmeyen bir Job başlatır, async ise await ile sonucunu aldığınız bir Deferred döndürür. Resmi ayrıntılar için Kotlin coroutine dokümantasyonuna bakabilirsiniz.

Structured concurrency ve coroutine scope neden önemlidir?

Structured concurrency, her coroutine'in bir scope'a bağlı olması ilkesidir. Scope iptal edildiğinde altındaki tüm coroutine'ler de iptal olur. Böylece ekran kapandığında arka planda unutulan ağ istekleri ve bellek sızıntılarını önlersiniz.

Android'de hazır scope'lar bu işi sizin yerinize üstlenir. viewModelScope, ViewModel temizlendiğinde; lifecycleScope ise yaşam döngüsü sahibi yok edildiğinde iptal olur. Bu nedenle GlobalScope kullanımını savunmak mülakatta genelde eksi puan getirir.

Hata yönetimi de bu sorunun devamıdır. Normal bir Job'da çocuk coroutine'lerden biri hata verirse kardeşleri de iptal olur; SupervisorJob ise hatayı yalnızca ilgili çocukta tutar. Üstelik CoroutineExceptionHandler'ın yalnızca kök coroutine'lerde işe yaradığını söylerseniz, konuyu gerçekten denediğinizi gösterirsiniz.

Flow, StateFlow ve SharedFlow arasındaki farklar nelerdir?

Flow soğuk bir akıştır: biri collect etmeden çalışmaz ve her toplayıcı için baştan başlar. StateFlow ve SharedFlow ise sıcak akıştır; toplayıcı olsa da olmasa da değer yayabilirler. Aşağıdaki tablo farkları özetliyor.

TürSoğuk mu sıcak mı?Başlangıç değeriTipik kullanım
FlowSoğukYokVeritabanı sorgusu, tek seferlik veri akışı
StateFlowSıcakZorunluEkran durumu (UI state)
SharedFlowSıcakİsteğe bağlı (replay)Tek seferlik olaylar, yayın
LiveDataSıcak, yaşam döngüsü farkındaİsteğe bağlıEski View tabanlı projeler

StateFlow aynı değeri art arda yaymaz, yani distinctUntilChanged davranışı vardır. Dolayısıyla aynı mesajı iki kez göstermek istediğiniz bir Snackbar olayı için StateFlow uygun değildir. Compose tarafında akışı toplarken collectAsStateWithLifecycle kullanmanız, uygulama arka plandayken gereksiz toplamayı durdurur.

Jetpack Compose nedir ve View sisteminden farkı nedir?

Jetpack Compose, Android için bildirimsel (declarative) arayüz araç setidir. XML ile görünüm ağacı kurup onu elle güncellemek yerine, arayüzü durumun bir fonksiyonu olarak yazarsınız. Durum değişince Compose ilgili kısmı yeniden çizer; buna recomposition denir.

Mülakatta bu farkı somut anlatmak işe yarar. View sisteminde bir TextView'ı findViewById ile bulup setText çağırırsınız. Compose'da ise yalnızca durumu değiştirirsiniz, gerisini çerçeve halleder. Google'ın Compose düşünce modeli sayfası bu yaklaşımı ayrıntılı anlatıyor.

@Composable
fun Selamlama(ad: String) {
    Text(text = "Merhaba, $ad")
}

Öte yandan Compose ile View sistemi birlikte de çalışabilir. ComposeView ile XML ekranına Compose, AndroidView ile Compose ekranına klasik View gömersiniz. Bu nedenle kademeli geçiş sorusuna "tek seferde yeniden yazmam, ekran ekran taşırım" yanıtı çoğu mülakatçıyı tatmin eder.

remember, rememberSaveable ve state hoisting nasıl çalışır?

remember, bir değeri recomposition'lar arasında hafızada tutar; ancak ekran döndürme gibi yapılandırma değişikliklerinde kaybolur. rememberSaveable ise değeri Bundle'a kaydeder, böylece yapılandırma değişikliği ve süreç ölümünden sonra da geri gelir.

@Composable
fun Sayac() {
    var sayi by rememberSaveable { mutableStateOf(0) }
    Button(onClick = { sayi++ }) { Text("Tıklama: $sayi") }
}

State hoisting ise durumu composable'dan yukarı, çağırana taşımaktır. Composable değeri ve bir onChange lambda'sını parametre olarak alır. Böylece bileşen durumsuz kalır, yeniden kullanılabilir ve test edilebilir olur. Kısacası tek doğruluk kaynağı ilkesini uygularsınız.

İyi bir aday, iş mantığı durumunun ViewModel'de, yalnızca arayüze ait geçici durumun (bir menünün açık olup olmadığı gibi) composable içinde kalması gerektiğini de söyler.

Android mülakat sorularında recomposition ve performans neden önemlidir?

Recomposition, bir composable'ın okuduğu State nesnesi değiştiğinde başlar. Compose yalnızca etkilenen composable'ları yeniden çalıştırmaya çalışır ve parametreleri değişmemiş, kararlı (stable) türdeki çağrıları atlayabilir.

Mülakatta sık sorulan performans önerileri şunlardır:

  1. Pahalı hesaplamaları remember içine alın, her çizimde tekrar hesaplamayın.
  2. Sık değişen bir durumdan türetilen değer için derivedStateOf kullanın.
  3. LazyColumn öğelerine key verin; liste değişince öğeler doğru eşleşir.
  4. Kaydırma pozisyonu gibi değerleri mümkün olduğunca geç okuyun, örneğin lambda tabanlı modifier ile.
  5. Değişmez veri sınıfları kullanın; değişken List yerine kararlı türleri tercih edin.

Ayrıca ölçmeden optimize etmemeniz gerektiğini söylemek artı puandır. Layout Inspector'daki recomposition sayaçları hangi composable'ın gereksiz yere çalıştığını gösterir. Aynı ölçme disiplinini web tarafında Lighthouse ile performans testinde de uyguluyorum.

Side effect API'lerini ne zaman kullanırsınız?

Composable fonksiyonlar yan etkisiz olmalıdır; çünkü ne zaman ve kaç kez çalışacaklarını siz belirlemezsiniz. Yine de bazen bir analitik olayı göndermeniz veya bir dinleyici kaydetmeniz gerekir. Compose bunun için kontrollü API'ler sunar.

  • LaunchedEffect: Anahtar değiştiğinde yeniden başlayan bir coroutine çalıştırır; örneğin bir Snackbar göstermek için.
  • rememberCoroutineScope: Bir tıklama gibi olay içinde coroutine başlatmanızı sağlar.
  • DisposableEffect: Kayıt ve temizleme gerektiren işler içindir; onDispose bloğu zorunludur.
  • SideEffect: Her başarılı recomposition sonrası Compose dışı bir nesneyi günceller.
  • produceState: Compose dışı bir kaynağı State'e dönüştürür.

Mülakatçı genelde LaunchedEffect(Unit) kullanımının ne anlama geldiğini sorar. Yanıt şudur: anahtar hiç değişmediği için efekt yalnızca composable ilk kez kompozisyona girdiğinde çalışır.

Activity ve Fragment yaşam döngüsü nasıl işler?

Activity yaşam döngüsü onCreate, onStart, onResume, onPause, onStop ve onDestroy çağrılarından oluşur. onStart ile ekran görünür, onResume ile kullanıcı etkileşimine açık hâle gelir. Resmi akışı Android Developers yaşam döngüsü rehberinde bulabilirsiniz.

Asıl ayırt edici soru yapılandırma değişikliğidir. Ekran döndüğünde Activity varsayılan olarak yok olur ve sistem onu yeniden oluşturur. Bu nedenle geçici arayüz durumunu ViewModel'de, küçük ve kritik durumu ise SavedStateHandle veya rememberSaveable ile saklarsınız.

Fragment tarafında ise iki yaşam döngüsü vardır: Fragment'in kendisi ve görünümünün (view) yaşam döngüsü. Örneğin bir Flow'u lifecycleScope yerine viewLifecycleOwner.lifecycleScope ile toplamazsanız, görünüm yok olduktan sonra da güncelleme yapmaya çalışabilirsiniz. Üstelik süreç ölümü (process death) sorusunu da buraya bağlayın: sistem arka plandaki uygulamayı öldürebilir ve yalnızca kaydedilmiş durum geri gelir.

Android'in dört temel bileşeni nelerdir?

Android uygulamasının dört temel bileşeni Activity, Service, BroadcastReceiver ve ContentProvider'dır. Her birini manifest dosyasında tanımlarsınız ve sistem her birini ayrı ayrı başlatabilir. Mülakatta her birinin ne zaman kullanıldığını bir cümleyle açıklamanızı ister.

  • Activity: Kullanıcının etkileşime girdiği ekran; modern uygulamalarda genelde tek Activity ve Compose ekranları olur.
  • Service: Arayüzsüz çalışan iş; kullanıcının fark ettiği uzun işler için bildirim gösteren foreground service gerekir.
  • BroadcastReceiver: Sistem veya uygulama yayınlarını dinler; örneğin cihaz açılışı.
  • ContentProvider: Veriyi diğer uygulamalarla güvenli biçimde paylaşır.

Ayrıca Intent sorusu bu başlığın devamıdır. Açık (explicit) Intent belirli bir bileşeni hedefler, örtük (implicit) Intent ise bir eylemi tanımlar ve sistem uygun uygulamayı bulur. Android 12 ve sonrasında intent filtresi olan bileşenlerde android:exported değerini açıkça belirtmeniz gerekir.

Arka plan işleri için WorkManager'ı ne zaman tercih edersiniz?

WorkManager, uygulama kapansa veya cihaz yeniden başlasa bile çalışması garanti edilmesi gereken ertelenebilir işler içindir. Örneğin fotoğraf yükleme, günlük senkronizasyon veya log gönderimi bu gruba girer. Kısıt (constraint) olarak ağ bağlantısı veya şarj durumu tanımlayabilirsiniz.

Mülakatta seçim sorusu genelde şöyle gelir: bu işi coroutine ile mi, WorkManager ile mi, foreground service ile mi yaparsınız? Kısa bir karar kuralı işinizi görür:

  1. İş yalnızca ekran açıkken anlamlıysa coroutine ve viewModelScope kullanın.
  2. İş kalıcı olmalı ve ertelenebiliyorsa WorkManager kullanın.
  3. İş hemen başlamalı ve kullanıcı bunu fark etmeliyse (müzik, navigasyon) foreground service kullanın.

Dolayısıyla "her şeyi Service ile yaparım" yanıtı güncel Android kısıtlamalarını bilmediğinizi gösterir. Pil optimizasyonu ve Doze modu nedeniyle sistem arka plan işlerini sıkı biçimde sınırlar.

ViewModel ve MVVM mimarisini nasıl kurarsınız?

ViewModel, arayüz durumunu yapılandırma değişikliklerinden koruyan ve iş mantığını ekrandan ayıran bir Jetpack bileşenidir. MVVM'de ekran yalnızca durumu gösterir ve kullanıcı olaylarını ViewModel'e iletir; ViewModel ise repository üzerinden veriyi alıp yeni durumu yayar.

Google'ın uygulama mimarisi rehberi bugün katmanlı bir yapı öneriyor: UI katmanı, isteğe bağlı domain katmanı ve veri katmanı. Veri tek yönde akar; durum aşağı iner, olaylar yukarı çıkar. Buna tek yönlü veri akışı (UDF) denir.

class ProfilViewModel(
    private val repo: ProfilRepository
) : ViewModel() {
    private val _state = MutableStateFlow<UiState>(UiState.Loading)
    val state: StateFlow<UiState> = _state.asStateFlow()
}

Mülakatçı genelde neden MutableStateFlow'u private tuttuğunuzu sorar. Yanıt: dışarıdan yalnızca okunabilir bir akış açarsınız, böylece durumu yalnızca ViewModel değiştirebilir. Öte yandan MVI sorusu gelirse, MVI'ın tüm olayları tek bir niyet (intent) akışında topladığını ve durumu tek bir nesnede tuttuğunu söyleyebilirsiniz.

Bağımlılık enjeksiyonu için Hilt'i nasıl kullanırsınız?

Hilt, Dagger üzerine kurulu ve Android için önerilen bağımlılık enjeksiyonu kütüphanesidir. Nesneleri kendiniz oluşturmak yerine, onların nasıl üretileceğini tanımlarsınız ve Hilt doğru kapsamda sağlar. Böylece test sırasında gerçek repository yerine sahte bir sürüm vermek kolaylaşır.

Temel anotasyonları bilmeniz yeterli başlangıç sağlar: uygulama sınıfında @HiltAndroidApp, Activity'de @AndroidEntryPoint, ViewModel'de @HiltViewModel, modüllerde @Module ve @InstallIn. Arayüz bağlamak için @Binds, üçüncü taraf nesneler için @Provides kullanırsınız.

Ayrıca kapsam (scope) sorusu sık gelir. @Singleton uygulama boyunca tek örnek üretir; @ViewModelScoped ise ViewModel ömrü boyunca yaşar. Yani her şeyi Singleton yapmak bellek ve test açısından sorun yaratır. Küçük projelerde Koin gibi alternatifleri de bildiğinizi, ancak derleme zamanı denetimi nedeniyle Hilt'i tercih ettiğinizi söyleyebilirsiniz.

Room ile yerel veriyi nasıl saklarsınız?

Room, SQLite üzerinde çalışan ve sorguları derleme zamanında doğrulayan bir kalıcılık kütüphanesidir. Üç parçadan oluşur: @Entity ile tablo, @Dao ile sorgular ve @Database ile veritabanı sınıfı. DAO fonksiyonları suspend olabilir veya Flow döndürebilir.

Flow döndüren bir sorgu, tablo değiştiğinde otomatik olarak yeni sonucu yayar. Bu nedenle çevrimdışı öncelikli (offline-first) mimaride veritabanı tek doğruluk kaynağı olur: ağdan gelen veri önce Room'a gider, arayüz yalnızca Room'u dinler.

Mülakatta migration sorusu da gelebilir. Şema değiştiğinde sürüm numarasını artırır ve bir Migration nesnesi ya da otomatik migration tanımlarsınız. fallbackToDestructiveMigration kullanmak kullanıcı verisini sildiği için üretimde dikkat ister. Açıkçası bu soruya dürüst bir "üretimde veri kaybı yaşadım, sonra migration testleri yazdım" hikâyesi en ikna edici yanıttır.

Android uygulamasında testi nasıl yazarsınız?

Android'de testleri üç katmanda ele alırsınız: birim testleri, entegrasyon testleri ve arayüz testleri. Birim testleri JVM üzerinde hızlı çalışır ve ViewModel ile repository mantığını doğrular. Arayüz testleri ise cihazda veya emülatörde çalışır.

Coroutine içeren kodu test ederken runTest ve test dispatcher kullanırsınız; böylece gecikmeler sanal zamanda anında geçer. Compose ekranları için createComposeRule ile düğümleri bulur, tıklar ve metni doğrularsınız. Flow testlerinde Turbine gibi kütüphaneler yayılan değerleri sırayla kontrol etmeyi kolaylaştırır.

Mülakatçı genelde test edilebilirliği mimariyle bağlar. Örneğin ViewModel içinde doğrudan Retrofit nesnesi oluşturursanız onu test etmek zorlaşır; bağımlılığı constructor ile verirseniz sahte bir repository geçirebilirsiniz. Test otomasyonunda araç seçimini merak ediyorsanız, web tarafındaki mobil uyumluluk testi rehberi de benzer bir disiplin anlatıyor.

Bellek sızıntısı ve performans sorunlarını nasıl bulursunuz?

Android'de en sık bellek sızıntısı, uzun ömürlü bir nesnenin kısa ömürlü bir Activity veya Context referansını tutmasıyla oluşur. Örneğin statik bir alanda Activity saklamak ya da bir dinleyiciyi kaydedip hiç kaldırmamak bu duruma yol açar.

Sahada kullandığım teşhis araçları şunlardır:

  • LeakCanary: Geliştirme sürümünde sızıntıları otomatik yakalar ve referans zincirini gösterir.
  • Android Studio Profiler: Bellek, işlemci ve ağ kullanımını canlı izler.
  • Baseline Profile: Açılış ve kaydırma performansını derleme optimizasyonuyla iyileştirir.
  • StrictMode: Ana thread'de disk veya ağ erişimini geliştirme sırasında yakalar.

ANR (Application Not Responding) sorusu da bu başlığa girer. Ana thread uzun süre bloklanırsa sistem kullanıcıya uygulamanın yanıt vermediğini söyler. Bu yüzden ağır işleri ana thread dışına taşırsınız. Web tarafında hızın sıralamaya etkisini site hızı ve SEO yazısında anlattım; mobil uygulamada da hız doğrudan kullanıcı puanına yansır.

Android mülakat sorularında canlı kodlama görevleri nelerdir?

Canlı kodlamada mülakatçı algoritma sorusundan çok, küçük ama gerçekçi bir ekran ister. Sahada en sık gördüğüm görevler şunlardır:

  1. Bir API'den liste çekip LazyColumn ile gösteren, yükleniyor ve hata durumlarını ele alan ekran.
  2. Arama kutusuna yazdıkça sonuçları filtreleyen, debounce uygulayan bir ViewModel.
  3. Bir formun alanlarını doğrulayan ve gönder düğmesini koşula bağlayan Compose ekranı.
  4. Room'a kaydedilen favorileri çevrimdışı da gösteren basit bir liste.

Burada mülakatçı kodun mükemmel olmasını beklemez; düşünme biçiminizi izler. Bu nedenle önce gereksinimi tekrar edin, sonra durum modelini (sealed interface) yazın, ardından ekranı kurun. Yazarken ne yaptığınızı sesli anlatın. Takıldığınız yerde varsayımınızı söylemek, sessizce beklemekten her zaman daha iyidir.

Örneğin debounce görevinde Flow üzerinde debounce, distinctUntilChanged ve flatMapLatest zincirini kurmak, coroutine bilginizi tek satırda gösterir.

Mülakata hazırlanırken hangi hatalardan kaçınmalısınız?

Yıllar içinde adaylarda en sık gördüğüm hatalar birbirine benziyor. Hazırlık planınızı bunlara göre kurarsanız, aynı teknik bilgiyle çok daha iyi bir izlenim bırakırsınız.

  • Yalnızca tanım ezberlemek; "neden" sorusu gelince yanıtsız kalmak.
  • Güncel olmayan yaklaşımları savunmak, örneğin AsyncTask veya GlobalScope.
  • Kendi projesindeki mimari kararları açıklayamamak.
  • Canlı kodlamada sessiz kalmak ve soru sormamak.
  • Neyi nasıl test edeceğini hiç planlamamış olmak.

Ayrıca portföy konusunu da hafife almayın. Play Store'da yayında küçük bir uygulama, uzun bir sertifika listesinden daha güçlü bir kanıttır. Uygulamanızın tanıtım sayfası varsa, mobil öncelikli tasarım ilkelerine uygun olması da profesyonel görünümünüzü destekler.

Kıdemli seviyede Android mülakat soruları nasıl değişir?

Kıdemli pozisyonlarda soruların odağı sözdiziminden karara kayar. Mülakatçı artık "StateFlow nedir?" diye sormaz; "on kişilik bir ekipte durum yönetimini nasıl standartlaştırırsınız?" diye sorar. Yani sizden gerekçeli seçim ve ödünleşim (trade-off) anlatımı bekler.

Bu seviyede sık gelen konular şunlardır: çok modüllü proje yapısı ve derleme süresi, Kotlin Multiplatform ile kod paylaşımının sınırları, çevrimdışı senkronizasyonda çakışma çözümü, uygulama boyutu ve açılış süresi optimizasyonu, CI üzerinde test ve sürüm otomasyonu. Örneğin modülleştirme sorusunda feature ve core modüllerini ayırmanın derleme önbelleğine etkisini anlatabilirsiniz.

Öte yandan kıdemli rolde iletişim de teknik bilgi kadar önem taşır. Ürün ekibine teknik borcu anlatabilmek, bir büyük ölçekli web mimarisinde micro frontend kararını savunmaya benzer; ikisinde de iş etkisini somut göstermeniz gerekir.

Android mülakat soruları için etkili bir çalışma planını nasıl kurarsınız?

Android mülakat soruları geniş bir alanı kapsadığı için plansız çalışmak zaman kaybettirir. Aşağıdaki dört haftalık plan, saha tecrübesine dayalı bir başlangıç önerisidir, garanti değildir; kendi seviyenize göre esnetebilirsiniz.

  1. 1. hafta: Kotlin temelleri, null güvenliği, koleksiyonlar ve scope fonksiyonlar. Her gün bir kavramı kısa kodla deneyin.
  2. 2. hafta: Coroutine, Flow ve test dispatcher. Küçük bir ağ isteği örneğini baştan sona yazın.
  3. 3. hafta: Jetpack Compose, state hoisting ve side effect API'leri. İki ekranlı bir uygulama kurun.
  4. 4. hafta: Mimari, Hilt, Room ve test. Projenizi temizleyip GitHub'a koyun ve mimarisini sesli anlatma provası yapın.

Kısacası her hafta sonunda bir arkadaşınızla deneme mülakatı yapmanızı öneririm. Kendi sesinizden yanıtları duymak, eksik kaldığınız yeri kâğıt üzerindeki çalışmadan çok daha hızlı gösterir.

Eğer bir uygulama ya da ürün için tanıtım sitesi, mağaza görünürlüğü veya arama motoru stratejisi planlıyorsanız, web tasarım hizmetime ve SEO danışmanlığı sayfama göz atabilirsiniz. Sorularınız için iletişim sayfasından bana doğrudan ulaşabilirsiniz.

Sıkça Sorulan Sorular

Android mülakatında Java bilmek gerekir mi?
Yeni projelerde çoğunlukla hayır, Kotlin yeterlidir. Ancak eski kod tabanlarında Java ile karşılaşırsınız ve Kotlin'in Java ile birlikte çalışmasını, platform türlerini ve @JvmStatic gibi anotasyonları bilmeniz beklenir. Bu nedenle Java'yı okuyabilecek düzeyde tutmanızı, yazma pratiğini ise Kotlin'e ayırmanızı öneririm. Bu yüzden bu konuyu önceden çalışmanız avantaj sağlar.
Jetpack Compose bilmeden Android işi bulunur mu?
Bulunur, fakat seçenekleriniz daralır. Birçok şirket hâlâ XML tabanlı ekranları sürdürüyor, ancak yeni ekranlar çoğunlukla Compose ile yazılıyor. Dolayısıyla mülakatta en az remember, state hoisting ve recomposition kavramlarını açıklayabilmeniz gerekir. Küçük bir Compose projesi bu açığı hızla kapatır. Kendi projenizden örnek vermeniz de fark yaratır.
Junior Android mülakatında en çok hangi konular sorulur?
Sahada en sık Kotlin null güvenliği, data class, Activity yaşam döngüsü, ViewModel ve basit coroutine kullanımı soruluyor. Bunlara ek olarak bir listeyi API'den çekip gösteren küçük bir ekran yazmanız istenebilir. Kıdem arttıkça sorular mimari, test ve performans kararlarına kayar. Kısacası temeli sağlam kurmanız yeterlidir.
Mülakat öncesi portföyde nasıl bir proje olmalı?
Tek ama temiz bir proje, beş yarım projeden daha etkilidir. MVVM ile kurulmuş, Hilt ve Room kullanan, birkaç birim testi olan ve README dosyasında mimari kararlarını açıklayan bir uygulama yeterlidir. Mümkünse Play Store'da yayınlayın; gerçek kullanıcıya ulaşmış kod güçlü bir kanıttır. Böylece mülakatta somut bir örnekle konuşursunuz.
LiveData hâlâ kullanılıyor mu?
Mevcut projelerde evet, ancak yeni kodda çoğu ekip StateFlow'u tercih ediyor. StateFlow coroutine dünyasıyla doğal biçimde çalışır ve Android'e bağımlı değildir. Mülakatta LiveData'nın yaşam döngüsü farkındalığını, StateFlow tarafında ise bunu collectAsStateWithLifecycle ile nasıl sağladığınızı anlatabilmelisiniz. Böylece iki yaklaşımı da rahatça savunursunuz.
Android mülakatına ne kadar sürede hazırlanılır?
Temel Kotlin bilginiz varsa dört hafta düzenli çalışma çoğu aday için yeterli bir başlangıçtır. Bu süre saha tecrübesine dayalı bir tahmindir, garanti değildir. Her gün bir konuyu kodla denemek ve haftada bir deneme mülakatı yapmak, uzun ama düzensiz çalışmadan daha verimli sonuç verir. Kısacası iki yöntemi de denemeniz faydalıdır.
#Android#Kotlin#Jetpack Compose#Mülakat Soruları#Mobil Geliştirme#Coroutine
Paylaş:
Talha Aslan
Talha Aslan

Google Partner dijital pazarlama uzmanı. 2012’den beri SEO, Google Ads, web tasarım ve e-ticaret projelerinde sahada; bu blogda gördüğünüz her yazı o deneyimden çıkar.

Sıradaki proje

Projenizi konuşalım.

Aracı yok, katman yok: doğrudan işi yapacak uzmanla konuşursunuz. İlk istişare ücretsizdir; hedefinizi dinler, net bir yol haritasıyla dönerim.

WhatsApp Hemen Ara