Skip to main content Link Menu Expand (external link) Document Search Copy Copied

Architecture recommendations

Recommendations for Android Architecture

Bu sayfada çeşitli Architecture best practiceleri ve önerileri sunulmaktadır. Uygulamanızın kalitesini, sağlamlığını ve ölçeklenebilirliğini artırmak için bunları benimseyin. Ayrıca uygulamanızın bakımını ve test edilmesini de kolaylaştırırlar.

Not: Bu belgedeki önerileri katı gereklilikler olarak değil tavsiyeler olarak ele almalısınız. Gerektiğinde bunları uygulamanıza uyarlayın.

Aşağıdaki best practiceler konuya göre gruplandırılmıştır. Her birinin, ekibin ne kadar güçlü bir şekilde önerdiğini yansıtan bir önceliği vardır. Öncelikler listesi aşağıdaki gibidir:

  • Strongly recommended: Yaklaşımınızla temelden çelişmediği sürece bu pratiği uygulamalısınız.
  • Recommended: Bu pratiğin uygulamanızı geliştirmesi muhtemeldir.
  • Optional: Bu pratik, belirli durumlarda uygulamanızı geliştirebilir.

Not: Bu önerileri anlamak için [Architecture kılavuzu](guide-to-app-architecture)na aşina olmanız gerekir.

Layer Architecture

Önerdiğimiz katmanlı mimari, seperation of concern’i destekler. UI’yi veri modellerinden yönlendirir, single source of truth ilkesine uyar ve undirectional data flow ilkelerini takip eder. İşte katmanlı mimari için bazı best practiceler:

RecommendationDescription
Açıkça tanımlanmış bir data katmanı kullanın.
Strongly recommended:
Data katmanı, uygulama verilerini uygulamanın geri kalanına sunar ve uygulamanızın business logic’inin büyük çoğunluğunu içerir.</br> * Sadece tek bir veri kaynağı içerse bile veri repositorylerini oluşturmalısınız. </br>* Küçük uygulamalarda, data katmanı türlerini bir data paketine veya modülüne yerleştirmeyi seçebilirsiniz
Açıkça tanımlanmış bir UI katmanı kullanın.
Strongly recommended:
UI katmanı, uygulama verilerini ekranda görüntüler ve kullanıcı etkileşiminin birincil noktası olarak hizmet eder.</br>* Küçük uygulamalarda, data katmanı tiplerini bir UI paketine veya modülüne yerleştirmeyi seçebilirsiniz.Daha fazla UI katmanı best practiceleri burada.
Data katmanı, bir repository kullanarak uygulama verilerini açığa çıkarmalıdır.
Strongly recommended:
UI katmanındaki componentler, activity’ler veya ViewModel’lar gibi componentler doğrudan bir veri kaynağı ile etkileşime girmemelidir. Veri kaynaklarına örnekler şunlardır: </br>* Databases, DataStore, SharedPreferences, Firebase APIs.</br> * GPS location providers. </br> * Bluetooth data providers.</br> * Network connectivity status provider.
Coroutines ve flowlari kullanin.
Strongly recommended:
Katmanlar arasında iletişim kurmak için coroutine’leri ve flow’ları kullanın. More coroutines best practices here.
Domain layer kullanin.
Recommended in big apps
Birden fazla ViewModel’de data katmanıyla etkileşime giren business logic’i yeniden kullanmanız gerekiyorsa veya belirli bir ViewModel’in business logic karmaşıklığını basitleştirmek istiyorsanız bir domain katmanı, use caseleri kullanın.

UI Layer

UI katmanının rolü, uygulama verilerini ekranda görüntülemek ve kullanıcı etkileşiminin birincil noktası olarak hizmet etmektir. İşte UI katmanı için bazı best practiceler:

RecommendationDescription
Unidirectional Data Flow (UDF’i takip edin..
Strongly recommended:
ViewModel’lerin observer pattern kullanarak UI state’ini gösterdiği ve metot çağrıları yoluyla UI’dan action’lar aldığı Unidirectional Data Flow (UDF) prensiplerini takip edin.
Faydaları uygulamanız için uygunsa AAC ViewModellerini kullanın.
Strongly recommended:
Business logic’i handle etmek için AAC ViewModels’i kullanın ve UI state’ini UI’ye göstermek için uygulama verilerini getirin (Compose veya Android Views).</br> See more ViewModel best practices here.</br>See the benefits of ViewModels here.
Yaşam döngüsüne duyarlı UI state collection kullanın.
Strongly recommended:
Uygun yaşam döngüsüne duyarlı coroutine builder kullanarak UI state’ini UI’dan collect edin: View sisteminde repeatOnLifecycle ve Jetpack Compose’da collectAsStateWithLifecycle.</br>Read more about repeatOnLifecycle.</br> Read more about about collectAsStateWithLifecycle.
ViewModel’den UI’ye event göndermeyin.
Strongly recommended:
Event’i ViewModel’de doğrudan işleyin ve event’in işlenmesinin sonucuyla bir state güncellemesine neden olun. UI event’leri hakkında daha fazla bilgiyi burada bulabilirsiniz.
Single-activity application kullanin.
Recommended
Uygulamanızın birden fazla ekranı varsa ekranlar arasında gezinmek ve uygulamanıza deep link vermek için Navigation Fragments veya Navigation Compose kullanın.
Jetpack Compose kullanin.
Recommended
Telefonlar, tabletler, katlanabilir cihazlar ve Wear OS için yeni uygulamalar oluşturmak üzere Jetpack Compose’u kullanın.

Aşağıdaki kod parçacığı, UI state’inin yaşam döngüsüne duyarlı bir şekilde nasıl collect edileceğini özetlemektedir:

//Views
class MyFragment : Fragment() {

    private val viewModel: MyViewModel by viewModel()

    override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
        super.onViewCreated(view, savedInstanceState)

        viewLifecycleOwner.lifecycleScope.launch {
            viewLifecycleOwner.repeatOnLifecycle(Lifecycle.State.STARTED) {
                viewModel.uiState.collect {
                    // Process item
                }
            }
        }
    }
}

//Compose
@Composable
fun MyScreen(
    viewModel: MyViewModel = viewModel()
) {
    val uiState by viewModel.uiState.collectAsStateWithLifecycle()
}

ViewModel

ViewModeller, UI state’ini sağlamaktan ve data katmanına erişimden sorumludur. ViewModel’ler için bazı best practiceler aşağıda verilmiştir:

RecommendationDescription
ViewModeller Android yaşam döngüsünden bağımsız olmalıdır.
Strongly recommended:
ViewModel’ler Yaşam Döngüsü ile ilgili herhangi bir tipe referans tutmamalıdır. Activity, Fragment, Context veya Resources’ı bağımlılık olarak geçirmeyin. Bir şeyin ViewModel’de bir Context’e ihtiyacı varsa, bunun doğru katmanda olup olmadığını mutlaka değerlendirmelisiniz.
Coroutine’leri ve flow’ları kullanın.
Strongly recommended:
ViewModel, data veya domain katmanları ile etkileşime girer:</br>Uygulama verilerini almak için Kotlin flow’ları,</br> viewModelScope kullanarak actionlari gerçekleştirmek için suspend fonksiyonlari kullanin.
Ekran seviyesinde ViewModelleri kullanın.</br> Strongly recommended:ViewModel’ları yeniden kullanılabilir UI parçalarında kullanmayın. ViewModel’leri şuralarda kullanmalısınız;</br>Screen-level composables,</br>Activities/Fragments in Views,</br>Destinations or graphs when using Jetpack Navigation.
Use plain state holder classes in reusable UI components.</br> Strongly recommended:Yeniden kullanılabilir UI component’lerinde karmaşıklığı ele almak için düz state holder sınıflarını kullanın. Bunu yaparak, state harici olarak çağrılabilir ve kontrol edilebilir.
AndroidViewModel kullanma.
Recommended
ViewModel class kullanin, AndroidViewModel kullanmayin. ViewModelde Application class kullanmamalisiniz. Bunun yerine, bağımlılığı UI veya data katmanına taşıyın.
Bir UI state açığa çıkarın.
Recommended
ViewModeller, uiState adlı single property aracılığıyla UI’ye veri göstermelidir. UI birden fazla, ilgisiz veri parçası gösteriyorsa, VM multiple UI state property gösterebilir.</br>uiState’i bir StateFlow yapmalısınız.</br>Veriler hiyerarşinin diğer katmanlarından bir veri akışı olarak geliyorsa, WhileSubscribed(5000) ilkesiyle (örnek) stateIn operatörünü kullanarak uiState oluşturmalısınız.</br>Data katmanından gelen veri akışlarının olmadığı daha basit durumlar için, immutable bir StateFlow olarak açığa çıkan bir MutableStateFlow kullanmak kabul edilebilir (örnek).</br>Data, error ve loading sinyalleri içerebilen bir data class olarak ${Screen}UiState’e sahip olmayı seçebilirsiniz. Bu sınıf, farklı statelerin özel olması halinde sealed class da olabilir.Application sınıfı ViewModel’de kullanılmamalıdır. Application sınıfı ViewModel’de kullanılmamalıdır. Bunun yerine, bağımlılığı kullanıcı arayüzüne veya veri katmanına taşıyın.

Aşağıdaki kod parçacığı, UI state’inin bir ViewModel’den nasıl açığa çıkarılacağını özetlemektedir:

@HiltViewModel
class BookmarksViewModel @Inject constructor(
    newsRepository: NewsRepository
) : ViewModel() {

    val feedState: StateFlow<NewsFeedUiState> =
        newsRepository
            .getNewsResourcesStream()
            .mapToFeedState(savedNewsResourcesState)
            .stateIn(
                scope = viewModelScope,
                started = SharingStarted.WhileSubscribed(5_000),
                initialValue = NewsFeedUiState.Loading
            )

    // ...
}

Lifecycle

Aşağıda Android yaşam döngüsü ile çalışmaya yönelik best practiceler yer almaktadır:

RecommendationDescription
Activity’lerde veya Fragment’larda yaşam döngüsü metotlarını override etmeyin.</br> Strongly recommended:Activity’lerde veya Fragment’larda onResume gibi yaşam döngüsü metodlarını override etmeyin. Bunun yerine LifecycleObserver kullanın. Uygulamanın, yaşam döngüsü belirli bir Lifecycle.State değerine ulaştığında iş yapması gerekiyorsa repeatOnLifecycle API’sini kullanın.

Aşağıdaki kod parçacığı, belirli bir Yaşam Döngüsü state’i verildiğinde işlemlerin nasıl gerçekleştirileceğini özetlemektedir:

//Views
class MyFragment: Fragment() {
    override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
        super.onViewCreated(view, savedInstanceState)

        viewLifecycleOwner.lifecycle.addObserver(object : DefaultLifecycleObserver {
            override fun onResume(owner: LifecycleOwner) {
                // ...
            }
            override fun onPause(owner: LifecycleOwner) {
                // ...
            }
        }
    }
}

//Compose
@Composable
fun MyApp() {

    val lifecycleOwner = LocalLifecycleOwner.current
    DisposableEffect(lifecycleOwner, ...) {
        val lifecycleObserver = object : DefaultLifecycleObserver {
            override fun onStop(owner: LifecycleOwner) {
                // ...
            }
        }

        lifecycleOwner.lifecycle.addObserver(lifecycleObserver)
        onDispose {
            lifecycleOwner.lifecycle.removeObserver(lifecycleObserver)
        }
    }
}

Handle dependencies

Componentler arasındaki bağımlılıkları yönetirken gözlemlemeniz gereken birkaç best practice vardir:

RecommendationDescription
Dependency injection kullanin.</br> Strongly recommended:Dependency injection best practiceleri kullanin, ozellikle mumkun oldugunca constructor injection kullanin.
Gerektiginde bir componentin scope’nu belirleyin.</br> Strongly recommended:Scope to a dependency container; tip paylaşılması gereken mutable veriler içerdiğinde veya tipin init edilmesi pahalı olduğunda ve uygulamada yaygın olarak kullanıldığında.
Hilt kullanin.
Recommended
Basit uygulamalarda Hilt veya manual dependency injection kullanin. Uygulamaniz karmasiklastiginda Hilt kullanin. Ornegin asagidakilere sahipseniz: </br>Multiple screens with ViewModels—integration</br>WorkManager usage—integration</br>Advance usage of Navigation, such as ViewModels scoped to the nav graph—integration.

Testing

Aşağıda test için bazı best practiceler verilmiştir:

RecommendationDescription
Neyi test edeceginizi bilin.
Strongly recommended:
Unless the project is roughly as simple as a hello world app, you should test it, at minimum with:</br>Unit test ViewModels, including Flows.</br>Unit test data layer entities. That is, repositories and data sources.</br>UI navigation tests that are useful as regression tests in CI.
Prefer fakes to mocks.
Strongly recommended:
Read more in the Use test doubles in Android documentation.
Test StateFlows.
Strongly recommended:
When testing StateFlow:</br>Assert on the value property whenever possible</br>You should create a collectJob if using WhileSubscribed

Daha fazla bilgi için Android DAC’da neleri test etmeli kılavuzuna bakın.

Models

Uygulamalarınızda model geliştirirken bu best practiceleri uymalısınız:

RecommendationDescription
Karmaşık uygulamalarda her katman için bir model oluşturun.
Recommended
Karmaşık uygulamalarda, mantıklı olduğunda farklı katmanlarda veya componentlerde yeni modeller oluşturun. Aşağıdaki örnekleri göz önünde bulundurun:</br>Uzak bir veri kaynağı, ağ üzerinden aldığı modeli, yalnızca uygulamanın ihtiyaç duyduğu verileri içeren daha basit bir sınıfla eşleyebilir</br>Repository’ler DAO modellerini sadece UI katmanının ihtiyaç duyduğu bilgilerle daha basit data classlara eşleyebilir.</br>ViewModel, UiState sınıflarındaki data katmanı modellerini içerebilir.

Naming Conventions

Kod tabanınızı adlandırırken, aşağıdaki best practice’lerden haberdar olmalısınız:

RecommendationDescription
Methodlari isimlendirmek.</br> Optional: Metodlar bir fiil cümlesi olmalıdır. Örneğin, makePayment().
Propertyleri isimlendirmek.</br> Optional: Propertyler bir isim cümlesi olmalıdır. Örneğin, inProgressTopicSelection.
Data akislarini isimlendirmek</br> Optional: Bir sınıf bir Flow stream, LiveData veya başka bir stream sunduğunda, adlandırma kuralı get{model}Stream() şeklindedir. Örneğin, getAuthorStream(): Flow. Fonksiyon bir model listesi döndürüyorsa, model adı çoğul olmalıdır:getAuthorsStream(): Flow<List>
Interface implementasyonlarini isimlendirmek.</br> Optional: Interfacelerin implementasyonları için isimler anlamlı olmalıdır. Daha iyi bir isim bulunamazsa önek olarak Default kullanın. Örneğin, bir NewsRepository interface’i için OfflineFirstNewsRepository veya InMemoryNewsRepository kullanabilirsiniz. Eğer iyi bir isim bulamazsanız, DefaultNewsRepository kullanın. Sahte implementasyonların önüne FakeAuthorsRepository’de olduğu gibi Fake eklenmelidir.