Panduan Pengembang Android untuk Pola Navigasi Fragmen

Diterbitkan: 2022-03-11

Selama bertahun-tahun, saya telah melihat banyak implementasi pola navigasi yang berbeda di Android. Beberapa aplikasi hanya menggunakan Aktivitas, sementara Aktivitas lainnya bercampur dengan Fragmen dan/atau dengan Tampilan Kustom.

Salah satu implementasi pola navigasi favorit saya didasarkan pada filosofi "Satu-Aktivitas-Beberapa-Fragmen", atau hanya Pola Navigasi Fragmen, di mana setiap layar dalam aplikasi adalah Fragmen layar penuh dan semua atau sebagian besar fragmen ini terkandung dalam satu Kegiatan.

Pendekatan ini tidak hanya menyederhanakan bagaimana navigasi diterapkan, tetapi juga memiliki kinerja yang jauh lebih baik dan akibatnya menawarkan pengalaman pengguna yang lebih baik.

Pada artikel ini kita akan melihat beberapa implementasi pola navigasi umum di Android, dan kemudian memperkenalkan pola navigasi berbasis Fragmen, membandingkan dan membedakan dengan yang lain. Aplikasi demo yang mengimplementasikan pola ini telah diunggah ke GitHub.

Dunia Kegiatan

Aplikasi Android tipikal yang hanya menggunakan aktivitas diatur ke dalam struktur seperti pohon (lebih tepatnya menjadi grafik terarah) di mana aktivitas root dimulai oleh peluncur. Saat Anda menavigasi dalam aplikasi, ada aktivitas back-stack yang dikelola oleh OS.

Contoh sederhana ditunjukkan pada diagram di bawah ini:

Fragmen gambar 1

Aktivitas A1 adalah titik masuk dalam aplikasi kita (misalnya, ini mewakili layar pembuka atau menu utama) dan darinya pengguna dapat menavigasi ke A2 atau A3. Saat Anda perlu berkomunikasi antar aktivitas, Anda dapat menggunakan startActivityForResult() atau mungkin Anda berbagi objek logika bisnis yang dapat diakses secara global di antara aktivitas tersebut.

Saat Anda perlu menambahkan Aktivitas baru, Anda perlu melakukan langkah-langkah berikut:

  • Tentukan aktivitas baru
  • Daftarkan di AndroidManifest.xml
  • Buka dengan startActivity() dari aktivitas lain

Tentu saja diagram navigasi ini merupakan pendekatan yang cukup sederhana. Ini bisa menjadi sangat kompleks saat Anda perlu memanipulasi back-stack atau saat Anda harus menggunakan kembali aktivitas yang sama beberapa kali, misalnya saat Anda ingin menavigasi pengguna melalui beberapa layar tutorial tetapi setiap layar sebenarnya menggunakan aktivitas yang sama sebagai basis.

Untungnya kami memiliki alat untuk itu yang disebut tugas dan beberapa pedoman untuk navigasi back-stack yang tepat.

Kemudian, dengan API level 11 muncul fragmen…

Dunia Fragmen

Android memperkenalkan fragmen di Android 3.0 (API level 11), terutama untuk mendukung desain UI yang lebih dinamis dan fleksibel pada layar besar, seperti tablet. Karena layar tablet jauh lebih besar daripada layar handset, ada lebih banyak ruang untuk menggabungkan dan menukar komponen UI. Fragmen memungkinkan desain seperti itu tanpa Anda perlu mengelola perubahan kompleks pada hierarki tampilan. Dengan membagi tata letak aktivitas menjadi fragmen, Anda dapat mengubah tampilan aktivitas saat runtime dan mempertahankan perubahan tersebut di back-stack yang dikelola oleh aktivitas. – dikutip dari panduan API Google untuk Fragmen.

Mainan baru ini memungkinkan pengembang untuk membangun UI multi-panel dan menggunakan kembali komponen dalam aktivitas lain. Beberapa pengembang menyukai ini sementara yang lain tidak. Ini adalah perdebatan populer apakah akan menggunakan fragmen atau tidak, tetapi saya pikir semua orang akan setuju bahwa fragmen membawa kompleksitas tambahan dan pengembang benar-benar perlu memahaminya agar dapat menggunakannya dengan benar.

Mimpi Buruk Fragmen Layar Penuh di Android

Saya mulai melihat semakin banyak contoh di mana fragmen tidak hanya mewakili bagian dari layar, tetapi sebenarnya seluruh layar adalah fragmen yang terkandung dalam suatu aktivitas. Saya bahkan pernah melihat desain di mana setiap aktivitas memiliki tepat satu fragmen layar penuh dan tidak lebih dan satu-satunya alasan mengapa aktivitas ini ada adalah untuk menampung fragmen-fragmen ini. Di samping cacat desain yang jelas, ada masalah lain dengan pendekatan ini. Perhatikan diagram dari bawah ini:

Fragmen gambar 2

Bagaimana cara A1 berkomunikasi dengan F1? Nah A1 memiliki kendali penuh atas F1 sejak ia menciptakan F1. A1 dapat melewati bundel, misalnya, pada pembuatan F1 atau dapat memanggil metode publiknya. Bagaimana F1 bisa berkomunikasi dengan A1? Nah ini lebih rumit, tapi bisa diselesaikan dengan pola callback/observer dimana A1 berlangganan F1 dan F1 memberitahu A1.

Tapi bagaimana A1 dan A2 bisa berkomunikasi satu sama lain? Ini sudah dibahas, misalnya melalui startActivityForResult() .

Dan sekarang pertanyaan sebenarnya muncul: bagaimana F1 dan F2 dapat berkomunikasi satu sama lain? Bahkan dalam hal ini kita dapat memiliki komponen logika bisnis yang tersedia secara global, sehingga dapat digunakan untuk melewatkan data. Tapi ini tidak selalu mengarah pada desain yang elegan. Bagaimana jika F2 perlu meneruskan beberapa data ke F1 dengan cara yang lebih langsung? Nah, dengan pola callback F2 bisa memberi tahu A2, lalu A2 selesai dengan hasil dan hasil ini ditangkap oleh A1 yang memberi tahu F1.

Pendekatan ini membutuhkan banyak kode boilerplate dan dengan cepat menjadi sumber bug, rasa sakit dan kemarahan.

Bagaimana jika kita bisa menyingkirkan semua aktivitas dan hanya menyimpan satu yang menyimpan sisa fragmen?

Pola Navigasi Fragmen

Selama bertahun-tahun saya mulai menggunakan pola "Satu-Aktivitas-Beberapa-Fragmen" di sebagian besar aplikasi saya dan saya masih menggunakannya. Ada banyak diskusi di luar sana tentang pendekatan ini, misalnya di sini dan di sini. Namun apa yang saya lewatkan adalah contoh nyata yang dapat saya lihat dan uji sendiri.

Mari kita lihat diagram berikut:

Gambar bingkai 3

Sekarang kami hanya memiliki satu aktivitas wadah dan kami memiliki beberapa fragmen yang memiliki struktur seperti pohon lagi. Navigasi di antara mereka ditangani oleh FragmentManager , ia memiliki back-stack.

Perhatikan bahwa sekarang kita tidak memiliki startActivityForResult() tetapi kita dapat mengimplementasikan pola callback/pengamat. Mari kita lihat beberapa pro dan kontra dari pendekatan ini:

Kelebihan:

1. Lebih bersih dan lebih mudah dirawat AndroidManifest.xml

Sekarang kita hanya memiliki satu Aktivitas, kita tidak perlu lagi memperbarui manifes setiap kali kita menambahkan layar baru. Tidak seperti aktivitas, kita tidak harus mendeklarasikan fragmen.

Ini mungkin tampak seperti hal kecil, tetapi untuk aplikasi yang lebih besar yang memiliki 50+ aktivitas, ini dapat meningkatkan keterbacaan file AndroidManifest.xml secara signifikan.

Lihatlah file manifes dari contoh aplikasi yang memiliki beberapa layar. File manifes masih tetap sangat sederhana.

 <?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. Manajemen navigasi terpusat

Dalam contoh kode saya, Anda akan melihat bahwa saya menggunakan NavigationManager yang dalam kasus saya disuntikkan ke setiap fragmen. Manajer ini dapat digunakan sebagai tempat terpusat untuk logging, manajemen back-stack, dan sebagainya, sehingga perilaku navigasi dipisahkan dari logika bisnis lainnya dan tidak tersebar dalam implementasi layar yang berbeda.

Mari kita bayangkan situasi di mana kita ingin memulai layar di mana pengguna dapat memilih beberapa item dari daftar orang. Anda juga ingin menyampaikan beberapa argumen pemfilteran seperti usia dan pekerjaan dan jenis kelamin.

Dalam hal Kegiatan, Anda akan menulis:

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

Maka Anda harus mendefinisikan onActivityResult di suatu tempat di bawah dan menangani hasilnya.

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

Masalah pribadi saya dengan pendekatan ini adalah bahwa argumen ini adalah "ekstra" dan tidak wajib, jadi saya harus memastikan bahwa aktivitas penerimaan menangani semua kasus yang berbeda ketika ada tambahan yang hilang. Kemudian ketika beberapa refactoring dibuat dan "umur" ekstra misalnya tidak lagi diperlukan, maka saya harus mencari di mana-mana di kode tempat saya memulai aktivitas ini dan memastikan bahwa semua ekstra sudah benar.

Selanjutnya, bukankah lebih baik jika hasil (daftar orang) akan datang dalam bentuk _Daftar _ dan bukan dalam bentuk serial yang harus di-deserialized?

Dalam hal navigasi berbasis fragmen, semuanya lebih mudah. Yang harus Anda lakukan adalah menulis metode di NavigationManager yang disebut startPersonSelectorFragment() dengan argumen yang diperlukan dan dengan implementasi callback.

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

Atau dengan RetroLambda

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

3. Sarana komunikasi yang lebih baik antar layar

Di antara aktivitas, kami hanya dapat berbagi Bundel yang dapat menyimpan data primitif atau serial. Sekarang dengan fragmen kita dapat menerapkan pola panggilan balik di mana misalnya, F1 dapat mendengarkan F2 melewati objek arbitrer. Silakan lihat implementasi callback contoh sebelumnya, yang mengembalikan _List _.

4. Fragmen Bangunan lebih murah daripada Aktivitas bangunan

Ini menjadi jelas ketika Anda menggunakan laci yang misalnya memiliki 5 item menu dan pada setiap halaman laci harus ditampilkan lagi.

Dalam hal navigasi aktivitas murni, setiap halaman harus mengembang dan menginisialisasi laci, yang tentu saja mahal.

Pada diagram di bawah ini Anda dapat melihat beberapa fragmen root (FR*) yang merupakan fragmen layar penuh yang dapat diakses langsung dari laci, dan juga laci hanya dapat diakses ketika fragmen ini ditampilkan. Segala sesuatu yang ada di sebelah kanan garis putus-putus dalam diagram ada sebagai contoh skema navigasi arbitrer.

Gambar bingkai 4

Karena aktivitas container menampung laci, kami hanya memiliki satu instance laci sehingga pada setiap langkah navigasi di mana laci harus terlihat, Anda tidak perlu mengembang dan menginisialisasinya lagi. Masih tidak yakin bagaimana semua ini bekerja? Lihatlah aplikasi sampel saya yang menunjukkan penggunaan laci.

Kontra

Ketakutan terbesar saya selalu bahwa jika saya menggunakan pola navigasi berbasis fragmen dalam sebuah proyek, di suatu tempat di jalan saya akan menghadapi masalah tak terduga yang akan sulit untuk memecahkan sekitar kompleksitas tambahan dari fragmen, perpustakaan pihak ke-3 dan versi OS yang berbeda. Bagaimana jika saya harus memperbaiki semua yang telah saya lakukan sejauh ini?

Memang, saya harus menyelesaikan masalah dengan fragmen bersarang, perpustakaan pihak ke-3 yang juga menggunakan fragmen seperti ShinobiControls, ViewPagers, dan FragmentStatePagerAdapters.

Saya harus mengakui bahwa mendapatkan pengalaman yang cukup dengan fragmen untuk dapat memecahkan masalah ini adalah proses yang agak panjang. Tetapi dalam setiap kasus, masalahnya bukan karena filosofinya buruk, tetapi karena saya tidak cukup memahami bagian-bagiannya. Mungkin jika Anda memahami fragmen lebih baik daripada saya, Anda bahkan tidak akan menghadapi masalah ini.

Satu-satunya kontra yang dapat saya sebutkan sekarang adalah bahwa kita masih dapat menghadapi masalah yang tidak akan sepele untuk dipecahkan karena tidak ada perpustakaan dewasa di luar sana yang menampilkan semua skenario kompleks dari aplikasi kompleks dengan navigasi berbasis fragmen.

Kesimpulan

Pada artikel ini, kita telah melihat cara alternatif untuk mengimplementasikan navigasi di aplikasi Android. Kami membandingkannya dengan filosofi navigasi tradisional yang menggunakan aktivitas dan kami telah melihat beberapa alasan bagus mengapa lebih menguntungkan menggunakannya daripada pendekatan tradisional.

Jika Anda belum melakukannya, lihat aplikasi demo yang diunggah ke implementasi GitHub. Jangan ragu untuk bercabang atau berkontribusi dengan contoh yang lebih bagus yang akan lebih baik menunjukkan penggunaannya.

Terkait: 10 Kesalahan Paling Umum Yang Dilakukan Pengembang Android