1. Giriş
Android cihaz ekosistemi sürekli olarak gelişiyor. Yerleşik klavyelerin ilk günlerinden katlanabilir, katlanabilir cihazlar, tabletler ve serbest biçimli yeniden boyutlandırılabilen pencerelerin modern ortamına kadar, Android uygulamaları bugüne kadar hiç bu kadar çok çeşitli cihazlarda çalışmamıştır.
Bu durum geliştiriciler için harika bir haber olsa da kullanılabilirlik beklentilerini karşılamak ve farklı ekran boyutlarında mükemmel bir kullanıcı deneyimi sunmak için bazı uygulama optimizasyonları gereklidir. Yeni cihazları teker teker hedeflemek yerine, duyarlı/uyarlanabilir kullanıcı arayüzü ve dayanıklı mimari, uygulamanızın mevcut ve gelecekteki kullanıcılarınızın bulunduğu her yerde, her boyut ve biçimdeki cihazlarda mükemmel görünmesini ve çalışmasını sağlayabilir.
Kullanıma sunulan, serbest biçimli, yeniden boyutlandırılabilen Android ortamları, duyarlı/uyarlanabilir kullanıcı arayüzünüzü tüm cihazlara hazır hale getirmek üzere baskı testi yapmanın harika bir yoludur. Bu kod laboratuvarı, yeniden boyutlandırmanın etkilerini anlamanın yanı sıra uygulamaları güvenli ve kolay bir şekilde yeniden boyutlandırmak için bazı en iyi uygulamalardan yararlanma konusunda size yol gösterecektir.
Ne oluşturacaksınız?
Serbest biçimde yeniden boyutlandırmanın etkilerini keşfedecek ve yeniden boyutlandırmayla ilgili en iyi uygulamaları göstermek için Android uygulamalarını optimize edeceksiniz. Uygulamanız şunları yapabilecek:
Uyumlu bir manifest dosyasıyla
- Uygulamanın serbest bir şekilde yeniden boyutlandırma yapmasını engelleyen kısıtlamaları kaldırma
Yeniden boyutlandırıldığında durumu koru
- rememberSaveable yöntemini kullanarak yeniden boyutlandırıldığında kullanıcı arayüzü durumunu korur
- Kullanıcı arayüzünü başlatmak için arka plan çalışmalarını gereksiz yere yinelemekten kaçının
Gerekenler
- Temel Android uygulamalarını oluşturma konusunda bilgi
- Compose'da ViewModel ve State bilgisi
- Aşağıdakilerden biri gibi, serbest biçimli pencere yeniden boyutlandırmasını destekleyen bir test cihazı:
- ADB kurulumu olan bir Chromebook
- Samsung DeX Modu'nu veya Verimlilik Modu'nu destekleyen bir tablet
- Android Studio'daki Masaüstü Android Sanal Cihaz emülatörü
Bu codelab'de çalışırken herhangi bir sorunla (kod hataları, dil bilgisi hataları, net olmayan ifadeler vb.) karşılaşırsanız lütfen codelab'in sol alt köşesindeki Hata bildir bağlantısını kullanarak sorunu bildirin.
2. Başlarken
Depoyu GitHub'dan klonlayın.
git clone https://github.com/android/large-screen-codelabs/
...veya deponun bir zip dosyasını indirip dosyayı çıkarın
Projeyi İçe Aktar
- Android Studio'yu açma
- Projeyi İçe Aktar veya Dosya->Yeni->Projeyi İçe Aktar'ı seçin.
- Projeyi klonladığınız veya çıkardığınız yere gidin
- resizing (Yeniden boyutlandırma) klasörünü açın.
- start klasöründe projeyi açın. Bu, başlangıç kodunu içerir.
Uygulamayı Deneyin
- Uygulamayı derleme ve çalıştırma
- Uygulamayı yeniden boyutlandırmayı deneyin
Ne düşünüyorsunuz?
Test cihazınızın uyumluluk desteğine bağlı olarak, kullanıcı deneyiminin ideal olmadığını fark etmiş olabilirsiniz. Uygulama yeniden boyutlandırılamıyor ve başlangıç en boy oranında takılı kaldı. What is happening?
Manifest kısıtlamaları
Uygulamanın AndroidManifest.xml
dosyasına bakarsanız uygulamamızın serbest biçimli pencere yeniden boyutlandırma ortamında iyi performans göstermesini engelleyen birkaç kısıtlama eklendiğini görebilirsiniz.
AndroidManifest.xml
android:maxAspectRatio="1.4"
android:resizeableActivity="false"
android:screenOrientation="portrait">
Bu üç sorunlu satırı manifest dosyanızdan kaldırıp uygulamayı yeniden oluşturun ve test cihazınızda tekrar deneyin. Uygulamanın artık serbest biçimde yeniden boyutlandırmanın kısıtlanmadığını fark edeceksiniz. Bu gibi kısıtlamaları manifest dosyanızdan kaldırmak, uygulamanızı serbest biçimli pencere yeniden boyutlandırması için optimize etme konusunda önemli bir adımdır.
3. Yeniden boyutlandırmayla ilgili yapılandırma değişiklikleri
Uygulamanızın penceresi yeniden boyutlandırıldığında uygulamanızın Yapılandırması güncellenir. Bu güncellemeler, uygulamanızı etkiler. Onları anlamak ve tahmin etmek kullanıcılarınıza harika bir deneyim sunmanıza yardımcı olabilir. En belirgin değişiklikler uygulama pencerenizin genişliği ve yüksekliğidir, ancak bu değişiklikler en boy oranı ve yönü de etkiler.
Yapılandırma değişikliklerini gözlemleme
Bu değişikliklerin, Android görüntüleme sistemiyle oluşturulmuş bir uygulamada kendiniz gerçekleştiğini görmek için View.onConfigurationChanged
politikasını geçersiz kılabilirsiniz. Jetpack Compose'da LocalConfiguration.current
erişimimiz var. Bu uygulama, View.onConfigurationChanged
çağrıldığında otomatik olarak güncellenir.
Örnek uygulamanızda bu yapılandırma değişikliklerini görmek için uygulamanıza LocalConfiguration.current
değerleri gösteren bir composable ekleyin veya böyle bir composable ile yeni bir örnek proje oluşturun. Bunları görmek için örnek bir kullanıcı arayüzü aşağıdaki gibi olacaktır:
val configuration = LocalConfiguration.current
val isPortrait = configuration.orientation ==
Configuration.ORIENTATION_PORTRAIT
val screenLayoutSize =
when (configuration.screenLayout and
Configuration.SCREENLAYOUT_SIZE_MASK) {
SCREENLAYOUT_SIZE_SMALL -> "SCREENLAYOUT_SIZE_SMALL"
SCREENLAYOUT_SIZE_NORMAL -> "SCREENLAYOUT_SIZE_NORMAL"
SCREENLAYOUT_SIZE_LARGE -> "SCREENLAYOUT_SIZE_LARGE"
SCREENLAYOUT_SIZE_XLARGE -> "SCREENLAYOUT_SIZE_XLARGE"
else -> "undefined value"
}
Column(
horizontalAlignment = Alignment.CenterHorizontally,
modifier = Modifier.fillMaxWidth()
) {
Text("screenWidthDp: ${configuration.screenWidthDp}")
Text("screenHeightDp: ${configuration.screenHeightDp}")
Text("smallestScreenWidthDp: ${configuration.smallestScreenWidthDp}")
Text("orientation: ${if (isPortrait) "portrait" else "landscape"}")
Text("screenLayout SIZE: $screenLayoutSize")
}
Örnek uygulamayı observing-configuration-changes proje klasöründe görebilirsiniz. Bunu uygulamanızın kullanıcı arayüzüne eklemeyi deneyin, test cihazınızda çalıştırın ve uygulamanızın yapılandırması değiştikçe kullanıcı arayüzü güncellemesini izleyin.
Uygulamanızın yapılandırmasında yapılan bu değişiklikler, küçük bir telefonda bölünmüş ekranla beklenen ekstrem durumlardan tablette veya masaüstünde tam ekrana geçişin hızlıca simülasyonunu yapmanıza olanak tanır. Bu, uygulamanızın ekranlardaki düzenini test etmenin iyi bir yolu olmanın yanı sıra uygulamanızın hızlı yapılandırma değişikliği etkinliklerini yönetmede ne kadar başarılı olduğunu test etmenize de olanak tanır.
4. Etkinlik yaşam döngüsü etkinliklerini günlüğe kaydetme
Uygulamanız için serbest biçimli pencere yeniden boyutlandırmasının bir diğer sonucu da uygulamanızda gerçekleşecek çeşitli Activity
yaşam döngüsü değişiklikleridir. Bu değişiklikleri gerçek zamanlı olarak görmek için onCreate
yönteminize bir yaşam döngüsü gözlemleyicisi ekleyin ve onStateChanged
işlemini geçersiz kılarak her yeni yaşam döngüsü etkinliğini günlüğe kaydedin.
lifecycle.addObserver(object : LifecycleEventObserver {
override fun onStateChanged(source: LifecycleOwner, event: Lifecycle.Event) {
Log.d("resizing-codelab-lifecycle", "$event was called")
}
})
Bu günlük kaydı yapıldıktan sonra uygulamanızı test cihazınızda tekrar çalıştırın ve uygulamanızı küçültüp tekrar ön plana getirmeye çalışırken logcat'e bakın.
Uygulamanızın küçültüldüğünde duraklatıldığını ve ön plana getirildiğinde tekrar başlatıldığını gözlemleyin. Bunun uygulamanız üzerindeki etkileri, bu codelab'in sürekliliğe odaklanan bir sonraki bölümünde incelenecek.
Şimdi, uygulamanızı mümkün olan en küçük boyuttan mümkün olan en büyük boyuta yeniden boyutlandırdığınızda hangi etkinlik yaşam döngüsü geri çağırmalarının çağrıldığını görmek için Logcat'e bakın.
Test cihazınıza bağlı olarak farklı davranışlar gözlemleyebilirsiniz, ancak muhtemelen uygulamanızın pencere boyutu önemli ölçüde değiştiğinde etkinliğinizin yok edildiğini ve yeniden oluşturulduğunu, ancak çok az bir değişiklik değiştirmediğini fark etmiş olabilirsiniz. Bunun nedeni, API 24 ve sonraki sürümlerde yalnızca önemli boyut değişikliklerinin Activity
yeniden oluşturulmasıyla sonuçlanmasıdır.
Serbest biçimli pencere ortamında bekleyebileceğiniz yaygın yapılandırma değişikliklerinden bazılarını gördünüz ancak bilmeniz gereken başka değişiklikler de var. Örneğin, test cihazınıza bağlı harici bir monitörünüz varsa Activity
cihazınızın yok edildiğini ve görüntü yoğunluğu gibi yapılandırma değişikliklerine uygun olacak şekilde yeniden oluşturulduğunu görebilirsiniz.
Yapılandırma değişiklikleriyle ilişkili karmaşıklığın bir kısmını soyutlamak amacıyla uyarlanabilir kullanıcı arayüzünüzü uygulamak için WindowSizeClass gibi daha yüksek düzey API'leri kullanın. (Ayrıca, Farklı ekran boyutlarını destekleme konusuna da bakın.)
5. Süreklilik - composables'ı koruma yeniden boyutlandırıldığında dahili durum
Önceki bölümde, serbest biçimli pencere yeniden boyutlandırma ortamında uygulamanızın bekleyebileceği bazı yapılandırma değişikliklerini gördünüz. Bu bölümde, bu değişiklikler boyunca uygulamanızın kullanıcı arayüzü durumunun sürekli olmasını sağlayacaksınız.
İlk olarak, NavigationDrawerHeader
composable işlevini (ReplyHomeScreen.kt
ürününde bulunur), tıklandığında e-posta adresini gösterecek şekilde genişletin.
@Composable
private fun NavigationDrawerHeader(
modifier: Modifier = Modifier
) {
var showDetails by remember { mutableStateOf(false) }
Column(
modifier = modifier.clickable {
showDetails = !showDetails
}
) {
Row(
horizontalArrangement = Arrangement.SpaceBetween,
verticalAlignment = Alignment.CenterVertically
) {
ReplyLogo(
modifier = Modifier
.size(dimensionResource(R.dimen.reply_logo_size))
)
ReplyProfileImage(
drawableResource = LocalAccountsDataProvider
.userAccount.avatar,
description = stringResource(id = R.string.profile),
modifier = Modifier
.size(dimensionResource(R.dimen.profile_image_size))
)
}
AnimatedVisibility (showDetails) {
Text(
text = stringResource(id = LocalAccountsDataProvider
.userAccount.email),
style = MaterialTheme.typography.labelMedium,
modifier = Modifier
.padding(
start = dimensionResource(
R.dimen.drawer_padding_header),
end = dimensionResource(
R.dimen.drawer_padding_header),
bottom = dimensionResource(
R.dimen.drawer_padding_header)
),
)
}
}
}
Genişletilebilir başlığı uygulamanıza eklediğinizde
- uygulamayı test cihazınızda çalıştırın
- genişletmek için başlığa dokunun
- pencereyi yeniden boyutlandırmayı deneyin
Başlığın önemli ölçüde yeniden boyutlandırıldığında durumunun kaybolduğunu görürsünüz.
remember
, durumu etkinlik veya işlem yeniden oluşturma genelinde değil, yeniden besteler genelinde korumanıza yardımcı olduğundan kullanıcı arayüzü durumu kayboldu. Durum kaldırma, durumu bir composable'ın çağrısına göre taşıma, composable'ları durum bilgisiz hale getirmek için yaygın bir uygulamadır. Bu sayede, bu sorundan tamamen kaçınabilirsiniz. Bununla birlikte, kullanıcı arayüzü öğesi durumunu composable işlevler için dahili tutarken remember
öğesini kullanabilirsiniz.
Bu sorunları gidermek için remember
yerine rememberSaveable
kullanın. Bu işlem, rememberSaveable
hatırlanan değeri savedInstanceState
hesabına kaydedip geri yüklediği için çalışır. remember
değerini rememberSaveable
olarak değiştirin, uygulamanızı test cihazında çalıştırın ve uygulamayı yeniden boyutlandırmayı deneyin. Genişletilebilir başlığın durumunun, istenen şekilde yeniden boyutlandırma boyunca korunduğunu fark edeceksiniz.
6. Arka plan çalışmalarının gereksiz yinelenmesini önleme
composable'ları korumak için rememberSaveable
'yi nasıl kullanabileceğinizi gördünüz. , serbest biçimli pencerenin yeniden boyutlandırması sonucu sık sık gerçekleşebilen yapılandırma değişiklikleri aracılığıyla dahili kullanıcı arayüzü durumunu gösterir. Ancak bir uygulama genellikle kullanıcı arayüzü durumunu ve mantığını composable'lardan uzaklaştırmalıdır. Durum sahipliğini ViewModel'e taşımak, yeniden boyutlandırma sırasında durumu korumanın en iyi yollarından biridir. Durumunuzu ViewModel
özelliğine taşırken yoğun dosya sistemi erişimi veya ekranınızı başlatmak için gereken ağ çağrıları gibi uzun süreli arka plan işleriyle ilgili sorunlarla karşılaşabilirsiniz.
Karşılaşabileceğiniz sorun türlerine ilişkin bir örnek görmek için ReplyViewModel
içerisindeki initializeUIState
yöntemine bir günlük ifadesi ekleyin.
fun initializeUIState() {
Log.d("resizing-codelab", "initializeUIState() called in the viewmodel")
val mailboxes: Map<MailboxType, List<Email>> =
LocalEmailsDataProvider.allEmails.groupBy { it.mailbox }
_uiState.value =
ReplyUiState(
mailboxes = mailboxes,
currentSelectedEmail = mailboxes[MailboxType.Inbox]?.get(0)
?: LocalEmailsDataProvider.defaultEmail
)
}
Şimdi uygulamayı test cihazınızda çalıştırın ve uygulamanızın penceresini birkaç kez yeniden boyutlandırmayı deneyin.
Logcat'e baktığınızda, uygulamanızın başlatma yönteminin birkaç kez çalıştığını fark edeceksiniz. Bu, kullanıcı arayüzünü başlatırken yalnızca bir kez çalıştırmak istediğiniz işler için sorun olabilir. Ek ağ çağrıları, dosya G/Ç veya diğer işler cihazın performansını düşürebilir ve istenmeyen başka sorunlara neden olabilir.
Gereksiz arka planda çalışmalardan kaçınmak için etkinliğinizin onCreate()
yönteminden initializeUIState()
çağrısını kaldırın. Bunun yerine, verileri ViewModel
öğesinin init
yönteminde başlatın. Bu, ReplyViewModel
ilk örneklendiğinde başlatma yönteminin yalnızca bir kez çalışmasını sağlar:
init {
initializeUIState()
}
Uygulamayı tekrar çalıştırmayı deneyin. Uygulamanızın penceresini kaç kez yeniden boyutlandırdığınıza bakılmaksızın, gereksiz simüle edilmiş başlatma görevinin yalnızca bir kez çalıştırıldığını görebilirsiniz. Bunun nedeni, ViewModel'lerin Activity
yaşam döngüsünden sonra da devam etmesidir. İlk kullanıma hazırlama kodunu, ViewModel
oluşturulurken yalnızca bir kez çalıştırarak, bu kodu tüm Activity
oluşturmalarından ayırır ve gereksiz çalışmaları önleriz. Bu gerçekten pahalı bir sunucu çağrısı veya kullanıcı arayüzünüzü başlatmak için yoğun bir dosya G/Ç işlemi olsaydı önemli miktarda kaynak tasarrufu yapar ve kullanıcı deneyiminizi iyileştirirdiniz.
7. TEŞEKKÜRLER!
Başardınız! İyi iş çıkardınız! Android uygulamalarının ChromeOS'te ve diğer çok pencereli, çok ekranlı ortamlarda iyi boyutlandırılmasına olanak tanımak için en iyi uygulamalardan bazılarını uygulamaya başladınız.
Örnek Kaynak Kodu
Depoyu GitHub'dan klonlama
git clone https://github.com/android/large-screen-codelabs/
...veya deponun bir zip dosyasını indirip dosyayı çıkarın