Kullanıcı arayüzü etkinlikleri, kullanıcı arayüzü katmanında kullanıcı arayüzü veya ViewModel tarafından işlenmesi gereken işlemlerdir. En yaygın etkinlik türü kullanıcı etkinlikleridir. Kullanıcı, uygulamayla etkileşimde bulunarak (örneğin, ekrana dokunarak veya hareketler oluşturarak) kullanıcı etkinlikleri oluşturur. Daha sonra kullanıcı arayüzü, onClick()
işleyicileri gibi geri çağırmaları kullanarak bu etkinlikleri tüketir.
Normalde ViewModel, belirli bir kullanıcı etkinliğinin iş mantığını yönetmekten sorumludur. Örneğin, kullanıcının bazı verileri yenilemek için bir düğmeyi tıklaması. ViewModel, genellikle bunu kullanıcı arayüzünün çağırabileceği işlevleri ortaya çıkararak yönetir. Kullanıcı etkinlikleri, kullanıcı arayüzünün doğrudan işleyebileceği (örneğin, farklı bir ekrana gitme veya bir Snackbar
gösterme) kullanıcı arayüzü davranış mantığına da sahip olabilir.
Aynı uygulamanın iş mantığı, farklı mobil platformlarda veya form faktörlerinde aynı kalırken kullanıcı arayüzü davranış mantığı, bu durumlar arasında farklılık gösterebilecek bir uygulama ayrıntısıdır. Kullanıcı arayüzü katmanı sayfasında bu mantık türleri şu şekilde tanımlanır:
- İş mantığı, durum değişiklikleriyle ne yapılacağını ifade eder (ör. ödeme yapma veya kullanıcı tercihlerini depolama). Bu mantığı genellikle alan ve veri katmanları uygular. Bu kılavuz boyunca Architecture Bileşenleri ViewModel sınıfı, iş mantığını işleyen sınıflar için fikirli bir çözüm olarak kullanılmıştır.
- Kullanıcı arayüzü davranış mantığı veya kullanıcı arayüzü mantığı, durum değişikliklerinin nasıl gösterileceğini ifade eder (örneğin, gezinme mantığı veya mesajların kullanıcıya nasıl gösterileceği). Kullanıcı arayüzü bu mantığı ele alır.
Kullanıcı arayüzü etkinliği karar ağacı
Aşağıdaki şemada, belirli bir etkinliğin kullanım alanını yönetmeye en uygun yaklaşımı bulmak için kullanabileceğiniz bir karar ağacı gösterilmektedir. Bu kılavuzun geri kalanında bu yaklaşımlar ayrıntılı olarak açıklanmaktadır.
![Etkinlik ViewModel'den geliyorsa kullanıcı arayüzü durumunu güncelleyin. Etkinlik kullanıcı arayüzünde oluşturulduysa ve iş mantığı gerektiriyorsa iş mantığını ViewModel'e atayın. Etkinlik kullanıcı arayüzünden kaynaklanıyorsa ve kullanıcı arayüzü davranış mantığı gerektiriyorsa kullanıcı arayüzü öğesinin durumunu doğrudan kullanıcı arayüzünden değiştirin.](https://developer.android.com/static/topic/libraries/architecture/images/mad-arch-uievents-tree.png?authuser=5&hl=tr)
Kullanıcı etkinliklerini işleme
Kullanıcı arayüzü, bir kullanıcı arayüzü öğesinin durumunun değiştirilmesiyle ilgiliyse (ör. genişletilebilir bir öğenin durumu) kullanıcı etkinliklerini doğrudan işleyebilir. Etkinlik, ekrandaki verileri yenilemek gibi bir iş mantığı gerektiriyorsa ViewModel tarafından işlenmelidir.
Aşağıdaki örnekte, bir kullanıcı arayüzü öğesini genişletmek (kullanıcı arayüzü mantığı) ve ekrandaki verileri yenilemek (iş mantığı) için farklı düğmelerin nasıl kullanıldığı gösterilmektedir:
Görüntüleme sayısı
class LatestNewsActivity : AppCompatActivity() {
private lateinit var binding: ActivityLatestNewsBinding
private val viewModel: LatestNewsViewModel by viewModels()
override fun onCreate(savedInstanceState: Bundle?) {
/* ... */
// The expand details event is processed by the UI that
// modifies a View's internal state.
binding.expandButton.setOnClickListener {
binding.expandedSection.visibility = View.VISIBLE
}
// The refresh event is processed by the ViewModel that is in charge
// of the business logic.
binding.refreshButton.setOnClickListener {
viewModel.refreshNews()
}
}
}
Oluştur
@Composable
fun LatestNewsScreen(viewModel: LatestNewsViewModel = viewModel()) {
// State of whether more details should be shown
var expanded by remember { mutableStateOf(false) }
Column {
Text("Some text")
if (expanded) {
Text("More details")
}
Button(
// The expand details event is processed by the UI that
// modifies this composable's internal state.
onClick = { expanded = !expanded }
) {
val expandText = if (expanded) "Collapse" else "Expand"
Text("$expandText details")
}
// The refresh event is processed by the ViewModel that is in charge
// of the UI's business logic.
Button(onClick = { viewModel.refreshNews() }) {
Text("Refresh data")
}
}
}
RecyclerViews'daki kullanıcı etkinlikleri
İşlem, kullanıcı arayüzü ağacının daha alt kısımlarında (ör. bir RecyclerView
öğesi veya özel bir View
) üretilirse kullanıcı etkinliklerini işleyen tek ViewModel
olmalıdır.
Örneğin, NewsActivity
sitesindeki tüm haber öğelerinde yer işareti düğmesi olduğunu varsayalım. ViewModel
uygulamasının, yer işareti eklenen haber öğesinin kimliğini bilmesi gerekir. Kullanıcı bir haber öğesine yer işareti koyduğunda RecyclerView
bağdaştırıcısı, ViewModel
üzerinden açık addBookmark(newsId)
işlevini çağırmaz. Bu da ViewModel
öğesine bağımlılığı gerektirir. Bunun yerine ViewModel
, etkinliği işlemek için uygulamayı içeren NewsItemUiState
adlı bir durum nesnesi gösterir:
data class NewsItemUiState(
val title: String,
val body: String,
val bookmarked: Boolean = false,
val publicationDate: String,
val onBookmark: () -> Unit
)
class LatestNewsViewModel(
private val formatDateUseCase: FormatDateUseCase,
private val repository: NewsRepository
)
val newsListUiItems = repository.latestNews.map { news ->
NewsItemUiState(
title = news.title,
body = news.body,
bookmarked = news.bookmarked,
publicationDate = formatDateUseCase(news.publicationDate),
// Business logic is passed as a lambda function that the
// UI calls on click events.
onBookmark = {
repository.addBookmark(news.id)
}
)
}
}
Bu şekilde, RecyclerView
bağdaştırıcısı yalnızca ihtiyaç duyduğu verilerle (NewsItemUiState
nesne listesiyle) çalışır. Bağdaştırıcının ViewModel'in tamamına erişimi olmadığından, ViewModel tarafından sunulan işlevselliği kötüye kullanma olasılığı daha düşüktür. ViewModel ile yalnızca etkinlik sınıfının çalışmasına izin verdiğinizde, sorumluluklarınızı ayırmış olursunuz. Bu, görünümler veya RecyclerView
bağdaştırıcıları gibi kullanıcı arayüzüne özgü nesnelerin ViewModel ile doğrudan etkileşimde bulunmamasını sağlar.
Kullanıcı etkinlik işlevleri için adlandırma kuralları
Bu kılavuzda, kullanıcı etkinliklerini işleyen ViewModel işlevleri, gerçekleştirdikleri işleme göre (örneğin: addBookmark(id)
veya logIn(username, password)
) bir fiille adlandırılmıştır.
ViewModel etkinliklerini işleme
ViewModel (ViewModel etkinlikleri) kaynaklı kullanıcı arayüzü işlemleri her zaman kullanıcı arayüzü durumu güncellemesiyle sonuçlanmalıdır. Bu, Tek Yönlü Veri Akışı ilkelerine uygundur. Bu, yapılandırma değişikliklerinden sonra etkinlikleri yeniden oluşturulabilir ve kullanıcı arayüzü işlemlerinin kaybolmayacağını garanti eder. İsteğe bağlı olarak, kaydedilmiş durum modülünü kullanıyorsanız işlem ölümünden sonra da etkinlikleri yeniden oluşturulabilir hale getirebilirsiniz.
Kullanıcı arayüzü işlemlerinin, kullanıcı arayüzü durumuyla eşleştirilmesi her zaman basit bir işlem olmasa da mantığın daha basit olmasını sağlar. Örneğin, düşünme süreciniz, kullanıcı arayüzünün belirli bir ekrana nasıl gideceğini belirlemekle bitmemelidir. Daha ayrıntılı düşünmeniz ve bu kullanıcı akışını kullanıcı arayüzü durumunuzda nasıl temsil edeceğinizi düşünmelisiniz. Başka bir deyişle: Kullanıcı arayüzünün yapması gereken işlemleri değil, bu işlemlerin kullanıcı arayüzü durumunu nasıl etkilediğini düşünün.
Örneğin, kullanıcı giriş ekranında oturum açtığında ana ekrana gitme durumunu ele alalım. Bunu kullanıcı arayüzü durumunda aşağıdaki şekilde modelleyebilirsiniz:
data class LoginUiState(
val isLoading: Boolean = false,
val errorMessage: String? = null,
val isUserLoggedIn: Boolean = false
)
Bu kullanıcı arayüzü, isUserLoggedIn
durumundaki değişikliklere tepki verir ve gerektiğinde doğru hedefe gider:
Görüntüleme sayısı
class LoginViewModel : ViewModel() {
private val _uiState = MutableStateFlow(LoginUiState())
val uiState: StateFlow<LoginUiState> = _uiState.asStateFlow()
/* ... */
}
class LoginActivity : AppCompatActivity() {
private val viewModel: LoginViewModel by viewModels()
override fun onCreate(savedInstanceState: Bundle?) {
/* ... */
lifecycleScope.launch {
repeatOnLifecycle(Lifecycle.State.STARTED) {
viewModel.uiState.collect { uiState ->
if (uiState.isUserLoggedIn) {
// Navigate to the Home screen.
}
...
}
}
}
}
}
Oluştur
class LoginViewModel : ViewModel() {
var uiState by mutableStateOf(LoginUiState())
private set
/* ... */
}
@Composable
fun LoginScreen(
viewModel: LoginViewModel = viewModel(),
onUserLogIn: () -> Unit
) {
val currentOnUserLogIn by rememberUpdatedState(onUserLogIn)
// Whenever the uiState changes, check if the user is logged in.
LaunchedEffect(viewModel.uiState) {
if (viewModel.uiState.isUserLoggedIn) {
currentOnUserLogIn()
}
}
// Rest of the UI for the login screen.
}
Etkinliklerin kullanılması durum güncellemelerini tetikleyebilir
Kullanıcı arayüzünde belirli ViewModel etkinliklerinin kullanılması, diğer kullanıcı arayüzü durum güncellemelerine neden olabilir. Örneğin, kullanıcıya bir şey olduğunu bildirmek için ekranda geçici mesajlar gösterilirken, mesaj ekranda gösterildiğinde başka bir durum güncellemesini tetiklemesi için kullanıcı arayüzünün ViewModel'e bildirimde bulunması gerekir. Kullanıcı mesajı kullandığında (mesajı kapatarak veya zaman aşımına uğradıktan sonra) gerçekleşen etkinlik, "kullanıcı girişi" olarak değerlendirilebilir ve ViewModel bu durumun farkında olmalıdır. Bu durumda, kullanıcı arayüzü durumu aşağıdaki gibi modellenebilir:
// Models the UI state for the Latest news screen.
data class LatestNewsUiState(
val news: List<News> = emptyList(),
val isLoading: Boolean = false,
val userMessage: String? = null
)
İş mantığı, kullanıcıya yeni bir geçici mesaj gösterilmesini gerektirdiğinde ViewModel, kullanıcı arayüzü durumunu aşağıdaki gibi günceller:
Görüntüleme sayısı
class LatestNewsViewModel(/* ... */) : ViewModel() {
private val _uiState = MutableStateFlow(LatestNewsUiState(isLoading = true))
val uiState: StateFlow<LatestNewsUiState> = _uiState
fun refreshNews() {
viewModelScope.launch {
// If there isn't internet connection, show a new message on the screen.
if (!internetConnection()) {
_uiState.update { currentUiState ->
currentUiState.copy(userMessage = "No Internet connection")
}
return@launch
}
// Do something else.
}
}
fun userMessageShown() {
_uiState.update { currentUiState ->
currentUiState.copy(userMessage = null)
}
}
}
Oluştur
class LatestNewsViewModel(/* ... */) : ViewModel() {
var uiState by mutableStateOf(LatestNewsUiState())
private set
fun refreshNews() {
viewModelScope.launch {
// If there isn't internet connection, show a new message on the screen.
if (!internetConnection()) {
uiState = uiState.copy(userMessage = "No Internet connection")
return@launch
}
// Do something else.
}
}
fun userMessageShown() {
uiState = uiState.copy(userMessage = null)
}
}
ViewModel'in kullanıcı arayüzünün ekrandaki mesajı nasıl gösterdiğini bilmesine gerek yoktur, yalnızca gösterilmesi gereken bir kullanıcı mesajı olduğunu bilir. Geçici mesaj gösterildikten sonra, kullanıcı arayüzünün ViewModel'i bu konuda bilgilendirmesi gerekir. Bu da, başka bir kullanıcı arayüzü durum güncellemesinin userMessage
özelliğini temizlemesine neden olur:
Görüntüleme sayısı
class LatestNewsActivity : AppCompatActivity() {
private val viewModel: LatestNewsViewModel by viewModels()
override fun onCreate(savedInstanceState: Bundle?) {
/* ... */
lifecycleScope.launch {
repeatOnLifecycle(Lifecycle.State.STARTED) {
viewModel.uiState.collect { uiState ->
uiState.userMessage?.let {
// TODO: Show Snackbar with userMessage.
// Once the message is displayed and
// dismissed, notify the ViewModel.
viewModel.userMessageShown()
}
...
}
}
}
}
}
Oluştur
@Composable
fun LatestNewsScreen(
snackbarHostState: SnackbarHostState,
viewModel: LatestNewsViewModel = viewModel(),
) {
// Rest of the UI content.
// If there are user messages to show on the screen,
// show it and notify the ViewModel.
viewModel.uiState.userMessage?.let { userMessage ->
LaunchedEffect(userMessage) {
snackbarHostState.showSnackbar(userMessage)
// Once the message is displayed and dismissed, notify the ViewModel.
viewModel.userMessageShown()
}
}
}
Mesaj geçici olsa da kullanıcı arayüzü durumu, zamandaki her noktada ekranda gösterilenleri aslı bir şekilde temsil eder. Kullanıcı mesajı gösteriliyor veya gösterilmiyor.
Gezinme etkinlikleri
Tüketim etkinlikleri, durum güncellemelerini tetikleyebilir bölümünde, kullanıcı mesajlarını ekranda görüntülemek için kullanıcı arayüzü durumunu nasıl kullanacağınız ayrıntılı olarak açıklanmaktadır. Gezinme etkinlikleri aynı zamanda Android uygulamalarında yaygın bir etkinlik türüdür.
Etkinlik, kullanıcı bir düğmeye dokunduğu için kullanıcı arayüzünde tetiklenirse kullanıcı arayüzü, gezinme denetleyicisini çağırarak veya etkinliği arayana uygun şekilde oluşturarak bunu gerçekleştirir.
Görüntüleme sayısı
class LoginActivity : AppCompatActivity() {
private lateinit var binding: ActivityLoginBinding
private val viewModel: LoginViewModel by viewModels()
override fun onCreate(savedInstanceState: Bundle?) {
/* ... */
binding.helpButton.setOnClickListener {
navController.navigate(...) // Open help screen
}
}
}
Oluştur
@Composable
fun LoginScreen(
onHelp: () -> Unit, // Caller navigates to the right screen
viewModel: LoginViewModel = viewModel()
) {
// Rest of the UI
Button(onClick = onHelp) {
Text("Get help")
}
}
Veri girişi, gezinmeden önce bazı iş mantığı doğrulaması gerektiriyorsa ViewModel'in bu durumu kullanıcı arayüzüne göstermesi gerekir. Kullanıcı arayüzü bu durum değişikliğine tepki verir ve buna göre gider. Bu kullanım alanını ViewModel etkinliklerini işleme bölümü ele alır. Benzer bir kod aşağıda verilmiştir:
Görüntüleme sayısı
class LoginActivity : AppCompatActivity() {
private val viewModel: LoginViewModel by viewModels()
override fun onCreate(savedInstanceState: Bundle?) {
/* ... */
lifecycleScope.launch {
repeatOnLifecycle(Lifecycle.State.STARTED) {
viewModel.uiState.collect { uiState ->
if (uiState.isUserLoggedIn) {
// Navigate to the Home screen.
}
...
}
}
}
}
}
Oluştur
@Composable
fun LoginScreen(
onUserLogIn: () -> Unit, // Caller navigates to the right screen
viewModel: LoginViewModel = viewModel()
) {
Button(
onClick = {
// ViewModel validation is triggered
viewModel.login()
}
) {
Text("Log in")
}
// Rest of the UI
val lifecycle = LocalLifecycleOwner.current.lifecycle
val currentOnUserLogIn by rememberUpdatedState(onUserLogIn)
LaunchedEffect(viewModel, lifecycle) {
// Whenever the uiState changes, check if the user is logged in and
// call the `onUserLogin` event when `lifecycle` is at least STARTED
snapshotFlow { viewModel.uiState }
.filter { it.isUserLoggedIn }
.flowWithLifecycle(lifecycle)
.collect {
currentOnUserLogIn()
}
}
}
Yukarıdaki örnekte, mevcut hedef (Giriş) arka yığında tutulmayacağı için uygulama beklendiği gibi çalışır. Kullanıcılar Geri düğmesine bastıklarında bu sayfaya geri dönemezler. Ancak böyle durumlarda çözüm için ek mantık gerekir.
Hedef arka yığında kaldığında gezinme etkinlikleri
Bir ViewModel, A ekranından B ekranına gezinme etkinliği oluşturan bir durum ayarlar ve A ekranı, gezinme geri yığınında tutulursa otomatik olarak B'ye ilerlemeyi sürdürmek için ek mantığa ihtiyacınız olabilir. Bunu uygulamak için kullanıcı arayüzünün diğer ekrana gitmeyi değerlendirmesi gerekip gerekmediğini belirten ek bir durumun olması gerekir. Normalde bu durum, gezinme mantığının ViewModel ile değil, kullanıcı arayüzü ile ilgili olması nedeniyle kullanıcı arayüzünde tutulur. Bunu göstermek için aşağıdaki kullanım alanını inceleyelim.
Uygulamanızın kayıt akışında olduğunuzu varsayalım. doğum tarihi doğrulama ekranında, kullanıcı bir tarih girdiği zaman kullanıcı "Devam" düğmesine dokunduğunda bu tarih ViewModel tarafından doğrulanır. ViewModel, doğrulama mantığını veri katmanına yetkilendirir. Tarih geçerliyse kullanıcı bir sonraki ekrana gider. Ek bir özellik olarak, kullanıcılar bazı verileri değiştirmek istemeleri ihtimaline karşı farklı kayıt ekranları arasında geçiş yapabilir. Bu nedenle, kayıt akışındaki tüm hedefler aynı arka yığında tutulur. Bu gereksinimleri göz önünde bulundurarak bu ekranı aşağıdaki şekilde uygulayabilirsiniz:
Görüntüleme sayısı
// Key that identifies the `validationInProgress` state in the Bundle
private const val DOB_VALIDATION_KEY = "dobValidationKey"
class DobValidationFragment : Fragment() {
private var validationInProgress: Boolean = false
private val viewModel: DobValidationViewModel by viewModels()
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState)
val binding = // ...
validationInProgress = savedInstanceState?.getBoolean(DOB_VALIDATION_KEY) ?: false
binding.continueButton.setOnClickListener {
viewModel.validateDob()
validationInProgress = true
}
viewLifecycleOwner.lifecycleScope.launch {
viewModel.uiState
.flowWithLifecycle(viewLifecycleOwner.lifecycle)
.collect { uiState ->
// Update other parts of the UI ...
// If the input is valid and the user wants
// to navigate, navigate to the next screen
// and reset `validationInProgress` flag
if (uiState.isDobValid && validationInProgress) {
validationInProgress = false
navController.navigate(...) // Navigate to next screen
}
}
}
return binding
}
override fun onSaveInstanceState(outState: Bundle) {
super.onSaveInstanceState(outState)
outState.putBoolean(DOB_VALIDATION_KEY, validationInProgress)
}
}
Oluştur
class DobValidationViewModel(/* ... */) : ViewModel() {
var uiState by mutableStateOf(DobValidationUiState())
private set
}
@Composable
fun DobValidationScreen(
onNavigateToNextScreen: () -> Unit, // Caller navigates to the right screen
viewModel: DobValidationViewModel = viewModel()
) {
// TextField that updates the ViewModel when a date of birth is selected
var validationInProgress by rememberSaveable { mutableStateOf(false) }
Button(
onClick = {
viewModel.validateInput()
validationInProgress = true
}
) {
Text("Continue")
}
// Rest of the UI
/*
* The following code implements the requirement of advancing automatically
* to the next screen when a valid date of birth has been introduced
* and the user wanted to continue with the registration process.
*/
if (validationInProgress) {
val lifecycle = LocalLifecycleOwner.current.lifecycle
val currentNavigateToNextScreen by rememberUpdatedState(onNavigateToNextScreen)
LaunchedEffect(viewModel, lifecycle) {
// If the date of birth is valid and the validation is in progress,
// navigate to the next screen when `lifecycle` is at least STARTED,
// which is the default Lifecycle.State for the `flowWithLifecycle` operator.
snapshotFlow { viewModel.uiState }
.filter { it.isDobValid }
.flowWithLifecycle(lifecycle)
.collect {
validationInProgress = false
currentNavigateToNextScreen()
}
}
}
}
Doğum tarihi doğrulaması, ViewModel'in sorumlu olduğu iş mantığıdır. Çoğu zaman ViewModel, bu mantığı veri katmanına aktarır. Bu gereksinimler kullanıcı arayüzü yapılandırmasına bağlı olarak değişebileceğinden, kullanıcıyı bir sonraki ekrana yönlendirme mantığı kullanıcı arayüzü mantığıdır. Örneğin, aynı anda birden çok kayıt adımı görüntülüyorsanız tablette otomatik olarak başka bir ekrana ilerlemek istemeyebilirsiniz. Yukarıdaki kodda bulunan validationInProgress
değişkeni bu işlevi uygular ve doğum tarihi geçerli olduğunda ve kullanıcı bir sonraki kayıt adımına devam etmek istediğinde kullanıcı arayüzünün otomatik olarak gidip gitmeyeceğini belirler.
Diğer kullanım alanları
Kullanıcı arayüzü etkinliği kullanım alanınızın, kullanıcı arayüzü durumu güncellemeleriyle çözülemeyeceğini düşünüyorsanız uygulamanızda veri akışını yeniden gözden geçirmeniz gerekebilir. Aşağıdaki ilkeleri göz önünde bulundurun:
- Her sınıf daha fazlasını değil, sorumlu olduğu işi yapmalıdır. Kullanıcı arayüzü; gezinme çağrıları, tıklama etkinlikleri ve izin istekleri alma gibi ekrana özgü davranış mantığından sorumludur. ViewModel, iş mantığını içerir ve hiyerarşinin alt katmanlarından gelen sonuçları kullanıcı arayüzü durumuna dönüştürür.
- Etkinliğin nereden geldiğini düşünün. Bu kılavuzun başında sunulan karar ağacını izleyin ve her sınıfın kendi sorumluluklarını yerine getirmesini sağlayın. Örneğin, etkinlik kullanıcı arayüzünden yapılıyorsa ve bir gezinme etkinliğiyle sonuçlanırsa bu etkinliğin kullanıcı arayüzünde işlenmesi gerekir. Bazı mantıklar ViewModel'e devredilebilir, ancak etkinliği işleme yetkisi ViewModel'e tamamen devredilemez.
- Birden fazla tüketiciniz varsa ve etkinliğin birden fazla kez tüketilmesinden endişeleniyorsanız uygulama mimarinizi yeniden gözden geçirmeniz gerekebilir. Aynı anda birden fazla tüketiciye sahip olmak, tam olarak bir kez teslim sözleşmesinin garanti edilmesini son derece zor hale getirir. Bu nedenle karmaşıklığı ve incelikli davranış miktarı artar. Bu sorunu yaşıyorsanız kullanıcı arayüzü ağacınızda bu kaygıları yukarıya iletmeyi düşünebilirsiniz. Hiyerarşide daha üst düzeylerde olan farklı bir varlığa ihtiyacınız olabilir.
- Eyaletin ne zaman tüketilmesi gerektiğini düşünün. Belirli durumlarda (örneğin,
Toast
gösterme gibi), uygulama arka plandayken veri tüketmeye devam etmek istemeyebilirsiniz. Bu durumlarda, kullanıcı arayüzünün ön plandaki durumunu kullanabilirsiniz.
Sana Özel
Aşağıdaki Google örnekleri, kullanıcı arayüzü katmanındaki kullanıcı arayüzü etkinliklerini göstermektedir. Bu kılavuzu inceleyerek örnekleri inceleyin:
Sizin için önerilenler
- Not: Bağlantı metni JavaScript kapalıyken gösterilir
- Kullanıcı arayüzü katmanı
- Eyalet sahipleri ve Kullanıcı Arayüzü Durumu {:#mad-arch}
- Uygulama mimarisi rehberi