Parça Gezinme Modeli için Android Geliştirici Kılavuzu

Yayınlanan: 2022-03-11

Yıllar boyunca, Android'de birçok farklı gezinme düzeni uygulaması gördüm. Uygulamalardan bazıları yalnızca Etkinlikleri kullanırken, diğerleri Parçalar ve/veya Özel Görünümlerle karışık Etkinlikler.

En sevdiğim gezinme düzeni uygulamalarından biri, “Tek Etkinlik-Çoklu Parçalar” felsefesine veya uygulamadaki her ekranın tam ekran bir Parça olduğu ve bu parçaların tümünün veya çoğunun bulunduğu Parça Gezinme Modeline dayanmaktadır. bir Etkinlik.

Bu yaklaşım yalnızca navigasyonun nasıl uygulandığını basitleştirmekle kalmaz, aynı zamanda çok daha iyi performansa sahiptir ve sonuç olarak daha iyi bir kullanıcı deneyimi sunar.

Bu makalede, Android'deki bazı yaygın gezinme düzeni uygulamalarına bakacağız ve ardından diğerleriyle karşılaştırarak ve karşılaştırarak Fragment tabanlı gezinme modelini tanıtacağız. Bu kalıbı uygulayan bir demo uygulaması GitHub'a yüklendi.

Aktiviteler Dünyası

Yalnızca etkinlikleri kullanan tipik bir Android uygulaması, kök etkinliğinin başlatıcı tarafından başlatıldığı ağaç benzeri bir yapıda (daha doğrusu yönlendirilmiş bir grafikte) düzenlenir. Uygulamada gezinirken, işletim sistemi tarafından sağlanan bir etkinlik arka yığını vardır.

Basit bir örnek aşağıdaki şemada gösterilmiştir:

Parça resmi 1

Etkinlik A1, uygulamamızdaki giriş noktasıdır (örneğin, bir açılış ekranını veya ana menüyü temsil eder) ve kullanıcı buradan A2 veya A3'e gidebilir. Aktiviteler arasında iletişim kurmanız gerektiğinde startActivityForResult() 'u kullanabilir veya belki aralarında global olarak erişilebilir bir iş mantığı nesnesi paylaşabilirsiniz.

Yeni bir Aktivite eklemeniz gerektiğinde aşağıdaki adımları uygulamanız gerekir:

  • Yeni aktiviteyi tanımlayın
  • AndroidManifest.xml dosyasına kaydedin
  • Başka bir aktiviteden startActivity() ile açın

Tabii ki bu navigasyon şeması oldukça basit bir yaklaşım. Arka yığını manipüle etmeniz gerektiğinde veya aynı aktiviteyi birden çok kez yeniden kullanmanız gerektiğinde, örneğin kullanıcıyı bazı eğitim ekranlarında gezinmek istediğinizde, ancak aslında her ekran aynı aktiviteyi kullandığında çok karmaşık hale gelebilir. temel.

Neyse ki, bunun için görevler adı verilen araçlarımız ve uygun arka yığın navigasyonu için bazı yönergelerimiz var.

Ardından, API seviyesi 11 ile parçalar geldi…

Parçaların Dünyası

Android, öncelikle tabletler gibi büyük ekranlarda daha dinamik ve esnek UI tasarımlarını desteklemek için Android 3.0'da (API seviye 11) parçaları tanıttı. Bir tabletin ekranı bir ahizeninkinden çok daha büyük olduğundan, UI bileşenlerini birleştirmek ve değiştirmek için daha fazla alan vardır. Parçalar, görünüm hiyerarşisindeki karmaşık değişiklikleri yönetmenize gerek kalmadan bu tür tasarımlara izin verir. Bir aktivitenin düzenini parçalara bölerek, aktivitenin çalışma zamanındaki görünümünü değiştirebilir ve bu değişiklikleri aktivite tarafından yönetilen bir arka yığında saklayabilirsiniz. – Fragmentler için Google'ın API kılavuzundan alıntılanmıştır.

Bu yeni oyuncak, geliştiricilerin çok bölmeli bir kullanıcı arabirimi oluşturmasına ve bileşenleri diğer etkinliklerde yeniden kullanmasına izin verdi. Bazı geliştiriciler bunu severken bazıları sevmez. Parçaların kullanılıp kullanılmaması popüler bir tartışmadır, ancak bence herkes parçaların ek karmaşıklık getirdiği konusunda hemfikirdir ve geliştiricilerin bunları doğru kullanmak için gerçekten anlamaları gerekir.

Android'de Tam Ekran Fragment Kabusu

Parçaların sadece ekranın bir bölümünü temsil etmediği, aslında tüm ekranın bir aktivitede yer alan bir parça olduğu giderek daha fazla örnek görmeye başladım. Bir keresinde, her aktivitenin tam olarak bir tam ekran parçasına sahip olduğu ve başka hiçbir şeyin olmadığı bir tasarım gördüm ve bu aktivitelerin var olmasının tek nedeni bu parçaları barındırmaktı. Belirgin tasarım kusurunun yanında, bu yaklaşımla ilgili başka bir sorun daha var. Aşağıdaki şemaya bir göz atın:

Parça resmi 2

A1, F1 ile nasıl iletişim kurabilir? A1, F1'i yarattığından beri F1 üzerinde tam kontrole sahiptir. A1, örneğin F1'in oluşturulmasında bir paket iletebilir veya genel yöntemlerini çağırabilir. F1, A1 ile nasıl iletişim kurabilir? Bu daha karmaşıktır, ancak A1'in F1'e abone olduğu ve F1'in A1'i bilgilendirdiği bir geri arama/gözlemci modeli ile çözülebilir.

Ancak A1 ve A2 birbirleriyle nasıl iletişim kurabilir? Bu, örneğin startActivityForResult() aracılığıyla zaten ele alınmıştır.

Ve şimdi asıl soru geliyor: F1 ve F2 birbirleriyle nasıl iletişim kurabilir? Bu durumda bile, küresel olarak kullanılabilen bir iş mantığı bileşenine sahip olabiliriz, bu nedenle veri iletmek için kullanılabilir. Ancak bu her zaman zarif bir tasarıma yol açmaz. F2'nin bazı verileri F1'e daha doğrudan bir şekilde iletmesi gerekiyorsa ne olur? Pekala, bir geri arama deseni ile F2, A2'yi bilgilendirebilir, ardından A2 bir sonuçla bitirir ve bu sonuç, F1'i bildiren A1 tarafından yakalanır.

Bu yaklaşım çok sayıda ortak koda ihtiyaç duyar ve hızla bir hata, acı ve öfke kaynağı haline gelir.

Ya tüm etkinliklerden kurtulup, geri kalan parçaları tutan sadece birini tutabilseydik?

Parça Gezinme Modeli

Yıllar geçtikçe, uygulamalarımın çoğunda “Bir-Etkinlik-Birden Çok Parça” modelini kullanmaya başladım ve hala kullanıyorum. Bu yaklaşım hakkında birçok tartışma var, örneğin burada ve burada. Ancak gözden kaçırdığım şey, kendim görebildiğim ve test edebildiğim somut bir örnek.

Aşağıdaki şemaya bir göz atalım:

Framgnet resmi 3

Şimdi sadece bir konteyner etkinliğimiz var ve yine ağaç benzeri bir yapıya sahip birden fazla parçamız var. Aralarındaki gezinme FragmentManager tarafından gerçekleştirilir, arka yığını vardır.

Artık startActivityForResult() 'a sahip olmadığımıza dikkat edin, ancak bir geri arama/gözlemci modeli uygulayabiliriz. Bu yaklaşımın bazı artılarını ve eksilerini görelim:

Artıları:

1. Daha temiz ve bakımı daha kolay AndroidManifest.xml

Artık sadece bir Aktivitemiz olduğuna göre, her yeni ekran eklediğimizde manifesti güncellememiz gerekmiyor. Aktivitelerin aksine, fragmanları bildirmek zorunda değiliz.

Bu küçük bir şey gibi görünebilir, ancak 50'den fazla etkinliği olan daha büyük uygulamalar için bu, AndroidManifest.xml dosyasının okunabilirliğini önemli ölçüde artırabilir.

Birkaç ekranı olan örnek uygulamanın manifest dosyasına bakın. Bildirim dosyası hala süper basit kalır.

 <?xml version="1.0" encoding="utf-8"?> package="com.exarlabs.android.fragmentnavigationdemo.ui" > <application android:name= ".FragmentNavigationDemoApplication" android:allowBackup="true" android:icon="@mipmap/ic_launcher" android:label="@string/app_name" android:supportsRtl="true" android:theme="@style/AppTheme"> <activity android:name="com.exarlabs.android.fragmentnavigationdemo.ui.MainActivity" android:label="@string/app_name" android:screenOrientation="portrait" android:theme="@style/AppTheme.NoActionBar" > <intent-filter> <action android:name="android.intent.action.MAIN" /> <category android:name="android.intent.category.LAUNCHER" /> </intent-filter> </activity> </application> </manifest>

2. Merkezi navigasyon yönetimi

Benim kod örneğimde, benim durumumda her parçaya enjekte edilen NavigationManager kullandığımı göreceksiniz. Bu yönetici, günlüğe kaydetme, arka yığın yönetimi vb. için merkezi bir yer olarak kullanılabilir, böylece gezinme davranışları iş mantığının geri kalanından ayrılır ve farklı ekranların uygulamalarında yayılmaz.

Kullanıcının bir kişi listesinden bazı öğeleri seçebileceği bir ekran başlatmak istediğimiz bir durumu hayal edelim. Ayrıca yaş, meslek ve cinsiyet gibi bazı filtreleme argümanlarını iletmek istersiniz.

Faaliyetler durumunda, şunu yazarsınız:

 Intent intent = new Intent(); intent.putExtra("age", 40); intent.putExtra("occupation", "developer"); intent.putExtra("gender", "female"); startActivityForResult(intent, 100);

Ardından, onActivityResult öğesini aşağıda bir yerde tanımlamanız ve sonucu işlemeniz gerekir.

 @Override protected void onActivityResult(int requestCode, int resultCode, Intent data) { super.onActivityResult(requestCode, resultCode, data); }

Bu yaklaşımla ilgili kişisel sorunum, bu argümanların “ekstralar” olması ve zorunlu olmamasıdır, bu nedenle, bir ekstra eksik olduğunda, alma faaliyetinin tüm farklı durumları ele aldığından emin olmalıyım. Daha sonra bazı yeniden düzenleme yapıldığında ve örneğin “yaş” ekstrasına artık ihtiyaç kalmadığında, bu aktiviteye başladığım kodun her yerinde arama yapmam ve tüm ekstraların doğru olduğundan emin olmam gerekiyor.

Ayrıca, sonucun (kişilerin listesi) bir _List biçiminde gelmesi daha iyi olmaz mıydı? _ ve seri hale getirilmesi gereken serileştirilmiş bir biçimde değil mi?

Parça tabanlı navigasyon durumunda, her şey daha basittir. Tek yapmanız gereken, NavigationManager'da startPersonSelectorFragment() adlı bir yöntemi gerekli bağımsız değişkenlerle ve bir geri çağırma uygulamasıyla yazmaktır.

 mNavigationManager.startPersonSelectorFragment(40, "developer", "female", new PersonSelectorFragment.OnPersonSelectedListener() { @Override public boolean onPersonsSelected(List<Person> selection) { [do something] return false; } });

Veya RetroLambda ile

 mNavigationManager.startPersonSelectorFragment(40, "developer", "female", selection -> [do something]);

3. Ekranlar arasında daha iyi iletişim araçları

Aktiviteler arasında yalnızca ilkelleri veya serileştirilmiş verileri tutabilen bir Bundle paylaşabiliriz. Şimdi parçalarla, örneğin F1'in rastgele nesnelerden geçen F2'yi dinleyebildiği bir geri arama modeli uygulayabiliriz. Lütfen önceki örneklerin bir _List geri döndüren geri arama uygulamasına bir göz atın. _.

4. Bina Parçaları, Bina Faaliyetlerinden daha ucuzdur

Bu, örneğin 5 menü öğesi içeren bir çekmece kullandığınızda ve her sayfada çekmecenin yeniden görüntülenmesi gerektiğinde belirginleşir.

Saf etkinlik navigasyonu durumunda, her sayfa elbette pahalı olan çekmeceyi şişirmeli ve başlatmalıdır.

Aşağıdaki şemada, doğrudan çekmeceden erişilebilen tam ekran parçaları olan birkaç kök parçası (FR*) görebilirsiniz ve ayrıca çekmeceye yalnızca bu parçalar görüntülendiğinde erişilebilir. Diyagramdaki kesikli çizginin sağındaki her şey, keyfi bir navigasyon şeması örneği olarak oradadır.

Framgnet resmi 4

Konteyner etkinliği çekmeceyi tuttuğundan, yalnızca bir çekmece örneğimiz var, böylece çekmecenin görünür olması gereken her gezinme adımında onu şişirip yeniden başlatmanız gerekmez. Hala tüm bunların nasıl çalıştığına ikna olmadınız mı? Çekmece kullanımını gösteren örnek uygulamama bir göz atın.

Eksileri

Her zaman en büyük korkum, bir projede parça tabanlı gezinme kalıbı kullanırsam, yolun aşağısında bir yerde, parçaların, 3. taraf kitaplıklarının ve farklı işletim sistemi sürümlerinin ek karmaşıklığı etrafında çözülmesi zor olan öngörülemeyen bir sorunla karşılaşacağımdı. Ya şimdiye kadar yaptığım her şeyi yeniden düzenlemem gerekirse?

Gerçekten de, ShinobiControls, ViewPagers ve FragmentStatePagerAdapters gibi parçaları da kullanan iç içe parçalar, 3. taraf kitaplıkları ile ilgili sorunları çözmem gerekiyordu.

Bu sorunları çözebilmek için fragmanlarla yeterli deneyim kazanmanın oldukça uzun bir süreç olduğunu itiraf etmeliyim. Ama her durumda mesele, felsefenin kötü olması değil, parçaları yeterince iyi anlamamış olmamdı. Belki fragmanları benden daha iyi anlasaydın bu sorunlarla karşılaşmazdın bile.

Şimdi bahsedebileceğim tek şey, parça tabanlı gezinme ile karmaşık bir uygulamanın tüm karmaşık senaryolarını gösteren olgun bir kitaplık olmadığı için çözülmesi önemsiz olmayan sorunlarla hala karşılaşabiliyor olmamızdır.

Çözüm

Bu makalede, bir Android uygulamasında gezinmeyi uygulamanın alternatif bir yolunu gördük. Aktiviteleri kullanan geleneksel navigasyon felsefesiyle karşılaştırdık ve onu geleneksel yaklaşıma göre kullanmanın neden avantajlı olduğuna dair birkaç iyi neden gördük.

Henüz yapmadıysanız, GitHub uygulamasına yüklenen demo uygulamasını inceleyin. Kullanımını daha iyi gösterecek daha güzel örneklerle çatallamaktan veya katkıda bulunmaktan çekinmeyin.

İlgili: Android Geliştiricilerinin Yaptığı En Yaygın 10 Hata