# Kotlin Coroutines Rehberi: Android için 2026 Kılavuzu > Android geliştirmede Kotlin coroutines konusunda uzmanlaşın: suspend fonksiyonlar, scope yapıları, dispatcher'lar ve ileri düzey kalıplar. - Published: 2026-01-04 - Updated: 2026-04-02 - Author: Anthony Fillion-Maillet - Tags: kotlin, coroutines, android, async, concurrency - Reading time: 12 min --- Kotlin coroutines, Android platformunda asenkron programlamanın temelini yeniden tanımladı. Callback karmaşası ve kullanımdan kaldırılan AsyncTask artık geride kaldı: coroutines sayesinde geliştiriciler, performanslı ve bakımı kolay olan asenkron kodu senkron bir yapıda yazabiliyor. > **Neden coroutines?** > > Coroutines hafiftir (tek bir iş parçacığında binlercesi çalışabilir), doğal olarak iptal edilebilir ve Jetpack ile modern Android ekosistemiyle sorunsuz entegre olur. ## Temelleri Anlamak Koda geçmeden önce, coroutines'i bu kadar güçlü kılan yapıyı anlamak gerekir. ### Coroutine Nedir? Coroutine, askıya alınabilir bir hesaplama örneğidir. İş parçacıklarından farklı olarak coroutines bloklamaz: yürütmeyi askıya alır ve iş parçacığını diğer görevler için serbest bırakır. ```kotlin // BasicCoroutine.kt import kotlinx.coroutines.* fun main() = runBlocking { launch { delay(1000L) // Suspend without blocking println("World!") } println("Hello,") } // Output: Hello, World! ``` ### Suspend Fonksiyonlar: Coroutines'in Kalbi `suspend` anahtar kelimesi, bir fonksiyonun iş parçacığını bloklamadan coroutine yürütmesini askıya alabileceğini belirtir. ```kotlin // SuspendFunction.kt suspend fun fetchUserData(userId: String): User { return withContext(Dispatchers.IO) { // Network call - runs on an IO thread apiService.getUser(userId) } } suspend fun fetchUserWithPosts(userId: String): UserWithPosts { // Sequential execution val user = fetchUserData(userId) val posts = fetchUserPosts(userId) return UserWithPosts(user, posts) } ``` > **Altın kural**: Bir suspend fonksiyon yalnızca başka bir suspend fonksiyondan veya bir coroutine kapsamından çağrılabilir. ## Coroutine Scope Yapıları Scope, coroutines'in yaşam döngüsünü belirler. Bellek sızıntılarını önlemek için kritik öneme sahiptir. ### viewModelScope: ViewModel'ler için Kapsam ```kotlin // UserViewModel.kt class UserViewModel( private val userRepository: UserRepository ) : ViewModel() { private val _uiState = MutableStateFlow(UserUiState.Loading) val uiState: StateFlow = _uiState.asStateFlow() fun loadUser(userId: String) { viewModelScope.launch { _uiState.value = UserUiState.Loading try { val user = userRepository.getUser(userId) _uiState.value = UserUiState.Success(user) } catch (e: Exception) { _uiState.value = UserUiState.Error(e.message) } } } } sealed class UserUiState { object Loading : UserUiState() data class Success(val user: User) : UserUiState() data class Error(val message: String?) : UserUiState() } ``` ### lifecycleScope: Activity ve Fragment'lar için ```kotlin // UserFragment.kt class UserFragment : Fragment() { private val viewModel: UserViewModel by viewModels() override fun onViewCreated(view: View, savedInstanceState: Bundle?) { super.onViewCreated(view, savedInstanceState) viewLifecycleOwner.lifecycleScope.launch { viewLifecycleOwner.repeatOnLifecycle(Lifecycle.State.STARTED) { viewModel.uiState.collect { state -> when (state) { is UserUiState.Loading -> showLoading() is UserUiState.Success -> showUser(state.user) is UserUiState.Error -> showError(state.message) } } } } } } ``` > **Sızıntılara dikkat** > > Bir Android uygulamasında asla `GlobalScope` kullanılmamalıdır. `GlobalScope` ile başlatılan coroutines'ler herhangi bir yaşam döngüsüne bağlı değildir ve bellek sızıntılarına neden olabilir. ## Dispatchers: Yürütme Kontrolü Dispatcher'lar, coroutine'in hangi iş parçacığında çalışacağını belirler. ### 4 Temel Dispatcher ```kotlin // Dispatchers.kt // Main: main thread (UI) viewModelScope.launch(Dispatchers.Main) { textView.text = "UI update" } // IO: I/O operations (network, database) viewModelScope.launch(Dispatchers.IO) { val data = repository.fetchFromNetwork() } // Default: CPU-intensive computations viewModelScope.launch(Dispatchers.Default) { val result = heavyComputation(data) } // Unconfined: inherits caller context (rare use) ``` ### withContext: Dispatcher Değiştirme ```kotlin // ImageProcessor.kt class ImageProcessor { suspend fun processImage(bitmap: Bitmap): Bitmap { return withContext(Dispatchers.Default) { // CPU-intensive processing on Default applyFilters(bitmap) } } suspend fun saveToGallery(bitmap: Bitmap) { withContext(Dispatchers.IO) { // Disk write on IO saveToFile(bitmap) } } } // Usage in ViewModel viewModelScope.launch { val processed = imageProcessor.processImage(originalBitmap) imageProcessor.saveToGallery(processed) // Automatic return to Main for UI update _uiState.value = UiState.Success(processed) } ``` ## async/await ile Paralel Yürütme Görevleri paralel olarak yürütmek ve sonuçları birleştirmek için `async` kullanılır. ```kotlin // ParallelExecution.kt suspend fun loadDashboard(): Dashboard { return coroutineScope { // Parallel launch val userDeferred = async { userRepository.getUser() } val statsDeferred = async { statsRepository.getStats() } val notificationsDeferred = async { notificationRepository.getNotifications() } // Await results Dashboard( user = userDeferred.await(), stats = statsDeferred.await(), notifications = notificationsDeferred.await() ) } } ``` > **Performans** > > `async` ile 3 çağrının tümü paralel olarak yürütülür. Her çağrı 1 saniye sürerse, toplam süre sıralı yürütmedeki 3 saniye yerine yaklaşık 1 saniye olur. ## Hata Yönetimi ### Klasik try/catch ```kotlin // ErrorHandling.kt viewModelScope.launch { try { val user = userRepository.getUser(userId) _uiState.value = UiState.Success(user) } catch (e: HttpException) { _uiState.value = UiState.Error("Server error: ${e.code()}") } catch (e: IOException) { _uiState.value = UiState.Error("Network error") } catch (e: Exception) { _uiState.value = UiState.Error("Unexpected error") } } ``` ### CoroutineExceptionHandler ```kotlin // ExceptionHandler.kt class UserViewModel : ViewModel() { private val exceptionHandler = CoroutineExceptionHandler { _, throwable -> _uiState.value = UiState.Error(throwable.message) Timber.e(throwable, "Error in coroutine") } fun loadUser(userId: String) { viewModelScope.launch(exceptionHandler) { val user = userRepository.getUser(userId) _uiState.value = UiState.Success(user) } } } ``` ### Result Wrapper Kalıbı ```kotlin // ResultPattern.kt sealed class Result { data class Success(val data: T) : Result() data class Error(val exception: Throwable) : Result() } suspend fun safeApiCall(apiCall: suspend () -> T): Result { return try { Result.Success(apiCall()) } catch (e: Exception) { Result.Error(e) } } // Usage class UserRepository(private val api: UserApi) { suspend fun getUser(id: String): Result = safeApiCall { api.getUser(id) } } // In ViewModel viewModelScope.launch { when (val result = userRepository.getUser(userId)) { is Result.Success -> _uiState.value = UiState.Success(result.data) is Result.Error -> _uiState.value = UiState.Error(result.exception.message) } } ``` ## İptal: Kaynakları Doğru Temizleme Coroutines, iş birlikçi iptal mekanizmasını destekler. Kaynak sızıntılarından kaçınmak için bu durum oldukça önemlidir. ### Scope ile Otomatik İptal ```kotlin // SearchViewModel.kt class SearchViewModel : ViewModel() { private var searchJob: Job? = null fun search(query: String) { // Cancel previous search searchJob?.cancel() searchJob = viewModelScope.launch { delay(300) // Debounce val results = searchRepository.search(query) _searchResults.value = results } } } ``` ### İptal Kontrolü ```kotlin // CancellationCheck.kt suspend fun processLargeList(items: List) { items.forEach { item -> // Check if coroutine is cancelled ensureActive() processItem(item) } } suspend fun downloadFiles(urls: List) = coroutineScope { urls.map { url -> async { try { downloadFile(url) } catch (e: CancellationException) { cleanupPartialDownload(url) throw e // Re-throw to propagate cancellation } } }.awaitAll() } ``` > **CancellationException asla yutulmamalıdır**: `Exception` yakalanırken `CancellationException` yeniden fırlatılmalıdır, böylece iptal mekanizması doğru şekilde yayılır. ## Flow: Reaktif Programlama Flow, RxJava Observable yapısının coroutines karşılığıdır ancak daha sade ve entegre bir çözüm sunar. ### Flow Oluşturma ve Toplama ```kotlin // FlowBasics.kt fun getUsers(): Flow> = flow { while (true) { val users = userApi.getUsers() emit(users) delay(5000) // Poll every 5 seconds } } // Flow from Room @Dao interface UserDao { @Query("SELECT * FROM users") fun getAllUsers(): Flow> } // Collecting in ViewModel viewModelScope.launch { userDao.getAllUsers() .catch { e -> _uiState.value = UiState.Error(e.message) } .collect { users -> _uiState.value = UiState.Success(users) } } ``` ### StateFlow ve SharedFlow Karşılaştırması ```kotlin // StateFlowVsSharedFlow.kt class EventViewModel : ViewModel() { // StateFlow: keeps last value, ideal for UI state private val _uiState = MutableStateFlow(UiState.Initial) val uiState: StateFlow = _uiState.asStateFlow() // SharedFlow: for one-shot events (navigation, snackbar) private val _events = MutableSharedFlow() val events: SharedFlow = _events.asSharedFlow() fun onButtonClick() { viewModelScope.launch { _events.emit(UiEvent.NavigateToDetail) } } } sealed class UiEvent { object NavigateToDetail : UiEvent() data class ShowSnackbar(val message: String) : UiEvent() } ``` ### Temel Flow Operatörleri ```kotlin // FlowOperators.kt userRepository.getUsers() .map { users -> users.filter { it.isActive } } .distinctUntilChanged() .debounce(300) .flatMapLatest { users -> fetchUserDetails(users) } .catch { e -> emit(emptyList()) } .onEach { users -> analytics.logUserCount(users.size) } .stateIn( scope = viewModelScope, started = SharingStarted.WhileSubscribed(5000), initialValue = emptyList() ) ``` ## İleri Düzey Kalıplar ### Üstel Geri Çekilme ile Yeniden Deneme ```kotlin // RetryPattern.kt suspend fun retryWithBackoff( times: Int = 3, initialDelay: Long = 100, maxDelay: Long = 1000, factor: Double = 2.0, block: suspend () -> T ): T { var currentDelay = initialDelay repeat(times - 1) { attempt -> try { return block() } catch (e: Exception) { Timber.w("Attempt ${attempt + 1} failed, retrying in ${currentDelay}ms") } delay(currentDelay) currentDelay = (currentDelay * factor).toLong().coerceAtMost(maxDelay) } return block() } // Usage val user = retryWithBackoff { userApi.getUser(userId) } ``` ### Zaman Aşımı ```kotlin // TimeoutPattern.kt suspend fun fetchWithTimeout() { try { val result = withTimeout(5000L) { api.fetchData() } processResult(result) } catch (e: TimeoutCancellationException) { showError("Request took too long") } } // Or with a default value val result = withTimeoutOrNull(5000L) { api.fetchData() } ?: defaultValue ``` ## Sonuc Kotlin coroutines, modern Android geliştirmenin vazgeçilmez bir parçası haline geldi. Jetpack ekosistemiyle tam uyumlu olan coroutines, asenkron programlamaya zarif ve yüksek performanslı bir yaklaşım sunmaktadır. ### Kontrol Listesi - Sızıntılardan kaçınmak için `viewModelScope` ve `lifecycleScope` kullanılmalıdır - Doğru Dispatcher seçilmelidir (Main, IO, Default) - Hatalar try/catch veya Result wrapper ile ele alınmalıdır - İş birlikçi iptal mekanizması uygulanmalıdır - Reaktif veri akışları için Flow kullanılmalıdır - UI durumu için StateFlow, olaylar için SharedFlow tercih edilmelidir Coroutines konusunda uzmanlaşmak, Android projelerinde ve teknik mülakatlarda önemli bir avantaj sağlayacaktır. Düzenli pratik yapmak ve ileri düzey kalıpları keşfetmek, bu alandaki yetkinliği daha da artıracaktır. --- Source: SharpSkill (https://sharpskill.dev), tech interview preparation for your real stack. HTML version of this page: https://sharpskill.dev/tr/blog/android/mastering-kotlin-coroutines