Android Uygulaması Yeniden Boyutlandırma

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

  1. Temel Android uygulamalarını oluşturma konusunda bilgi
  2. Compose'da ViewModel ve State bilgisi
  3. Aşağıdakilerden biri gibi, serbest biçimli pencere yeniden boyutlandırmasını destekleyen bir test cihazı:

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.

Uygulama yeniden boyutlandırıldığında, değişen yapılandırma bilgileri uygulamanın arayüzünde gerçek zamanlı olarak görüntülenir

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.

Yeniden boyutlandırma sırasında çağrılan etkinlik yaşam döngüsü yöntemlerinin gösterildiği logcat

Ş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

  1. uygulamayı test cihazınızda çalıştırın
  2. genişletmek için başlığa dokunun
  3. pencereyi yeniden boyutlandırmayı deneyin

Başlığın önemli ölçüde yeniden boyutlandırıldığında durumunun kaybolduğunu görürsünüz.

Uygulamanın gezinme çekmecesindeki başlığa dokunuluyor ve genişliyor, ancak uygulama yeniden boyutlandırıldıktan sonra daralıyor

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