Bagaimana kami menerapkan navigasi dari Jetpack ke dalam aplikasi pertempuran. Yandex. Laporan Makanan

Aplikasi seluler semakin banyak menggunakan tautan dalam. Ini adalah tautan yang memungkinkan Anda untuk tidak hanya pergi ke aplikasi dari luar, tetapi juga ke layar tertentu. Vladislav Kozhushko, pengembang Android dari Yandex.Food, menjelaskan mengapa kami menerapkan navigasi dari Jetpack untuk mengimplementasikan tautan dalam, masalah apa yang kami temui, bagaimana mereka dipecahkan dan apa yang terjadi pada akhirnya.


- Halo semuanya! Nama saya Vlad. Saya telah tertarik dengan pengembangan Android sejak 2013, saya telah bekerja di Yandex.Ed sejak musim panas lalu. Saya akan memberi tahu Anda tentang cara kami memperkenalkan perpustakaan Komponen Navigasi ke dalam aplikasi pertempuran.

Semuanya dimulai dengan fakta bahwa kami memiliki tugas teknis navigasi ulang refactoring. Kemudian manajer produk mendatangi kami dan mengatakan bahwa kami akan melakukan deeplink, akan ada banyak dari mereka, mereka akan mengarah ke layar yang berbeda.

Dan di sini kami pikir - navigasi yang disajikan di Google I / O 2018 sangat cocok untuk pelaksanaan tugas pada tautan dalam. Kami memutuskan untuk melihat apa yang terjadi. Rekan kami dengan iOS di Xcode memiliki editor grafis yang nyaman di mana mereka dapat menggunakan mouse untuk menyodok seluruh tata letak layar, serta mengatur transisi antar layar. Sekarang kita juga memiliki kesempatan seperti itu, kita dapat menggunakan mouse untuk mengatur transisi, tautan dalam ke layar dan mengaitkannya dengan fragmen. Selain itu, kita dapat mengatur argumen di layar.



Artinya, argumen harus terjebak di editor UI, atau ditulis dalam XML. Selain beralih di antara layar, tag tindakan muncul, di mana kami menunjukkan id dan layar yang harus kami tuju.



Kami juga menunjukkan deeplink yang ingin kami buka layarnya. Dalam hal ini, ada parameter itemId, jika kita melewatkan parameter semacam ini, dan itu akan mengarah ke sebuah fragmen, maka nilai parameter ini akan diteruskan ke argumen fragmen, dan kita bisa mendapatkan dan menggunakannya dengan kunci itemId. Perpustakaan juga mendukung uplink. Jika kita mengatur uplink, misalnya, navdemo.ru/start/{itemId}, maka kita tidak perlu lagi khawatir mendaftar skema http / https untuk membuka diplinks tersebut. Perpustakaan akan melakukan segalanya untuk kita.

Sekarang mari kita bicara tentang argumennya. Kami menambahkan dua argumen, integer dan boolean, dan juga memberi mereka nilai default.



Setelah itu, ketika merakit fragmen, kita akan memiliki kelas NextFragmentArgs. Ini memiliki Builder yang dengannya Anda dapat mengumpulkan dan mengatur argumen yang kita butuhkan. Ada juga getter di kelas NextFragmentArgs untuk mendapatkan argumen kami. Anda dapat mengumpulkan NextFragmentArgs dari bundle dan mengonversi bundle, yang sangat nyaman.



Tentang fitur utama perpustakaan. Dia memiliki editor UI yang nyaman di mana kita dapat melakukan semua navigasi. Kami mendapatkan markup XML yang dapat dibaca yang mengembang dengan cara yang sama seperti Views. Dan kami tidak memiliki kesulitan seperti yang dilakukan pengembang iOS ketika mereka memperbaiki sesuatu di editor grafis, dan banyak hal berubah.

Deeplinks dapat berfungsi baik dengan fragmen maupun dengan Activity, dan untuk ini Anda tidak perlu mendaftarkan IntentFilter dalam jumlah besar dalam manifes. Kami juga mendukung uplink, dan dengan Android 6 Anda dapat mengaktifkan autoverify untuk verifikasi. Selain itu, saat merakit proyek, pembuatan kode dilakukan dengan argumen ke layar yang diinginkan. Navigasi mendukung grafik bersarang dan navigasi bersarang, yang memungkinkan Anda mendekomposisi seluruh navigasi menjadi subkomponen terpisah.



Sekarang kita akan berbicara tentang jalan kita, yang telah kita lalui, memperkenalkan perpustakaan. Semuanya dimulai dengan versi alpha 3. Kami menerapkan semuanya, kami mengganti semua navigasi dengan komponen Navigasi, semuanya super, semuanya berfungsi, membuka diplink, tetapi masalah muncul.



Masalah pertama adalah IllegalArgumentException. Muncul dalam dua kasus: ketidakkonsistenan grafik, karena ada desinkronisasi representasi grafik dan fragmen pada tumpukan, karena ini ada pengecualian. Masalah kedua adalah klik ganda. Ketika kami membuat klik pertama, kami menavigasi. Pergi ke layar berikutnya, dan keadaan grafik berubah. Ketika kami membuat klik kedua, grafik sudah dalam keadaan baru, dan sedang mencoba untuk membuat transisi lama, yang tidak lagi ada, jadi kami mendapatkan pengecualian seperti itu. Dalam versi ini, diplink tidak terbuka, skema yang berisi titik, misalnya, proyek.perusahaan. Ini diputuskan dalam versi perpustakaan yang akan datang, dan dalam versi stabil semuanya bekerja dengan baik.

Juga, elemen yang dibagikan tidak didukung. Anda mungkin melihat cara kerja Google Play: ada daftar aplikasi, Anda mengklik aplikasi, layar Anda terbuka, dan animasi yang indah untuk memindahkan ikon terjadi. Kami juga memiliki ini dalam aplikasi pada daftar restoran, tetapi kami membutuhkan dukungan untuk elemen bersama. SafeArgs juga tidak bekerja untuk kami, jadi kami hidup tanpanya.



Mudah untuk memperbaiki tautan dalam. Itu perlu untuk mengganti skema yang ada di perpustakaan dengan skema sendiri, yang mendukung intinya. Dengan bantuan refleksi, kita mengetuk kelas, mengubah nilai regex, dan semuanya berfungsi.



Untuk memperbaiki klik ganda, kami menggunakan metode berikut. Kami memiliki fungsi ekstensi untuk mengatur klik dalam navigasi. Setelah mengklik tombol atau elemen lain, kami memperbarui ClickListener dan melakukan navigasi untuk menghindari transisi ganda. Atau jika Anda memiliki RxJava di proyek Anda, saya sarankan menggunakan perpustakaan RxBindingsgs dari Jake Worton, dan dengan itu Anda dapat menangani acara dari View dengan gaya reaktif, menggunakan operator yang tersedia untuk kami.



Mari kita bicara tentang elemen yang dibagikan. Karena mereka muncul sedikit kemudian, kami memutuskan untuk menyelesaikan navigator, tambahkan navigasi ke sana. Kami adalah programmer, mengapa tidak?



Penyempurnaan adalah sebagai berikut: kami mewarisi navigator kami dari navigator, yang ada di perpustakaan. Tidak semua kode disajikan di sini, tetapi ini adalah bagian utama yang telah kami selesaikan. Saya ingin mencatat bahwa sebelum melakukan navigasi, status FragmentManager diperiksa. Jika disimpan, maka kami kehilangan tim kami. Menurut saya, ini cacat.

Juga, ketika kami memulai transaksi fragmen, kami membuat transaksi dan mengatur semua Tampilan kami yang perlu digeledah. Tetapi pertanyaannya adalah, kelas seperti apakah TransitionDestination ini? Ini adalah kelas khusus kami untuk mengatur Tampilan. Kami mewarisinya dari Tujuan dan memperluas fungsionalitas. Kami menetapkan Tampilan dan Tujuan kami siap untuk membagikannya.



Bagian selanjutnya - kita perlu melakukan navigasi. Ketika kita mengklik tombol, kita mencari tujuan id, kita menarik keluar bagian atas grafik yang harus kita tuju. Setelah itu, kami akan mengubahnya menjadi TransitionDestination, di mana kami memiliki Views. Selanjutnya, kami mengatur semua Tampilan kami untuk menghidupkan transisi, dan melakukan navigasi. Semuanya berfungsi, semuanya super. Tapi kemudian alpha06 muncul.

Ini tidak berarti bahwa kami melakukan lompatan antar versi. Kami mencoba memperbarui perpustakaan sesuai kebutuhan, tetapi mungkin ini adalah perubahan paling mendasar yang kami temui.

Ada masalah dengan alpha06. Karena ini adalah versi alpha dari perpustakaan, ada perubahan konstan yang terkait dengan metode penamaan kembali, panggilan balik, antarmuka, belum lagi fakta bahwa parameter ditambahkan dan dihapus dalam metode. Karena kami menulis navigator kami sendiri, kami harus menyinkronkan kode navigator perpustakaan dengan kami untuk mengisi perbaikan bug dan fitur baru.

Juga, di perpustakaan itu sendiri, ketika kita beralih dari versi alpha awal ke versi stabil, perilaku telah berubah, beberapa fitur telah dihapus. Dulu ada flag launchDocument, tetapi tidak pernah digunakan, kemudian dihapus.



Misalnya, ada perubahan di mana pengembang mengatakan bahwa metode navigUp (), yang berfungsi dengan DrawerLayout, sudah tidak digunakan lagi, gunakan yang lain, di mana parameter hanya ditukar.





Migrasi besar kami berikutnya adalah di alpha11. Di sini memperbaiki masalah utama dengan navigasi saat bekerja dengan grafik. Kami akhirnya melepas pengontrol doped kami dan menggunakan semua yang ada di luar kotak. Argumen yang aman masih tidak bekerja untuk kami, dan kami kesal.

Kemudian beta01 dirilis, dan dalam versi ini hampir tidak ada yang berubah selama perilaku navigasi, tetapi masalah berikut muncul: jika sejumlah layar terbuka di aplikasi, maka kami menghapus tumpukan sebelum membuka diplink kami. Perilaku ini tidak cocok untuk kita. Argumen yang aman masih tidak berfungsi.



Kami menulis masalah di Google, di mana kami diberitahu bahwa semua aturan awalnya disusun, dan dalam kode itu sendiri ini karena sebelum beralih ke tautan dalam, kami kembali ke fragmen root menggunakan id dari grafik yang terletak di root. Dan juga dalam metode setPopUpTo () flag yang sebenarnya dilewati, mengatakan bahwa setelah kembali ke layar ini, kita juga perlu membuangnya dari tumpukan.



Kami memutuskan untuk mengembalikan navigator doped kami dan memperbaiki apa yang kami anggap salah.



Ini dia, masalah asli yang menyebabkan tumpukannya hilang. Kami menyelesaikannya sebagai berikut. Kami memeriksa apakah startDestination sama dengan nol, layar awal, maka kami akan menggunakannya, ambil sebagai pengidentifikasi pengenal grafik. Jika ID startDestination kami tidak sama dengan nol, maka kami akan mengambil ID ini dari grafik, karena itu kami tidak dapat menghapus tumpukan dan membuka diplink di atas konten yang kami miliki. Atau, sebagai opsi, Anda dapat menghapus pop-up true di opsi navigasi. Secara teori, semuanya harus bekerja juga.

Dan akhirnya, versi stabil keluar. Kami senang, kami berpikir bahwa semuanya baik-baik saja, tetapi dalam versi stabil, perilaku, pada umumnya, tidak berubah. Mereka baru saja menyelesaikannya. Kami akhirnya berhasil menggunakan arg aman, jadi kami mulai aktif menambahkan argumen di layar kami dan menggunakannya di mana-mana dalam kode. Kami juga menemukan bahwa navigasi tidak berfungsi dengan DialogFragments. Karena kami memiliki DialogFragments, kami ingin mentransfer semuanya ke grafik, dalam XML, dan mendeskripsikan transisi di antara mereka. Tetapi kami tidak berhasil.



Pembukaan ganda. Kami juga memiliki masalah yang menghantui kami dari versi pertama - pembukaan ganda Kegiatan selama awal yang dingin dari aplikasi.



Itu terjadi sebagai berikut. Ada metode deeplink handle yang hebat yang bisa kita panggil dari kode kita, misalnya, ketika dalam aktivitas kita mendapatkan onNewIntent () untuk mencegat deeplink. Di sini, bendera ACTIVITY_NEW_TASK muncul di Intent ketika aplikasi diluncurkan menggunakan tautan dalam, jadi yang berikut ini terjadi: Aktivitas baru dimulai, dan jika ada Aktivitas saat ini, ia terbunuh. Karena itu, jika kami meluncurkan aplikasi, layar putih dimulai terlebih dahulu, kemudian menghilang, layar lain muncul, dan mereka terlihat sangat indah.

Alhasil, dengan memperkenalkan perpustakaan ini, kami mendapat keuntungan sebagai berikut.



Kami memiliki dokumentasi untuk navigasi kami, serta representasi grafis dari transisi antara layar, dan jika seseorang datang kepada kami dalam suatu proyek, ia dengan cepat memahami ini dengan melihat grafik, membuka presentasinya di Studio.

Kami memiliki SingleActivity. Semua layar dibuat pada fragmen, semua diplink mengarah ke fragmen, dan saya pikir ini nyaman.

Hasilnya adalah tautan sederhana dari deeplink dengan fragmen, cukup tambahkan tag deeplink ke fragmen, dan perpustakaan melakukan segalanya untuk kita. Kami juga membagi navigasi kami menjadi subgraf bersarang, membuat navigasi bersarang. Ini adalah hal yang berbeda. Sebenarnya hanya grafik bersarang, itu termasuk di dalam grafik, dan navigasi bersarang adalah ketika navigator terpisah digunakan untuk berjalan di sekitar layar.

Kami juga mengubah grafik secara dinamis dalam kode, kami dapat menambahkan simpul, kami dapat menghapus simpul, kami dapat mengubah layar mulai - semuanya berfungsi.

Kami hampir lupa bagaimana bekerja dengan FragmentManager, karena semua logika bekerja dengannya dikemas di dalam perpustakaan, dan perpustakaan melakukan semua keajaiban bagi kami. Perpustakaan juga berfungsi dengan DrawerLayout, jika Anda memiliki set fragmen root, perpustakaan itu sendiri akan menggambar hamburger di atasnya, dan ketika pergi ke layar berikutnya, itu akan menggambar panah dan melakukannya dengan animasi ketika kembali dari fragmen kedua dari belakang.

Kami juga mentransfer semua argumen, sebagian besar, ke SafeArgs, dan semuanya dibuat saat kami membangun proyek. Selain itu, kami mengatasi semua masalah yang mengganggu kami, dan memodifikasi perpustakaan agar sesuai dengan kebutuhan kami.

SafeArgs dapat menghasilkan kode Kotlin, plugin terpisah digunakan untuk ini.



Selain itu, perpustakaan memiliki kekurangan. Yang pertama adalah bahwa pembersihan tumpukan dikirim ke versi stabil. Saya tidak tahu mengapa ini dilakukan, mungkin itu sangat nyaman bagi seseorang, tetapi dalam hal aplikasi kami, kami ingin membuka tautan dalam di atas konten yang kami miliki.

Fragmen-fragmen itu sendiri diciptakan oleh fragmen navigator, dan diciptakan melalui refleksi. Saya rasa ini bukan nilai tambah dalam implementasinya. Kondisi untuk deeplink tidak didukung. Aplikasi Anda mungkin memiliki layar rahasia yang hanya tersedia untuk pengguna yang berwenang. Dan untuk membuka deeplink berdasarkan ketentuan, Anda perlu menulis kruk untuk ini, karena Anda tidak dapat mengatur prosesor deeplink di mana kami akan mendapatkan kontrol dan mengatakan apa yang harus dilakukan, baik membuka layar dengan deeplink atau membuka layar lain.

Juga, perintah transisi hilang, semua karena fragmen navigator memeriksa keadaan apakah itu disimpan atau tidak, dan jika itu disimpan, maka kita tidak melakukan apa-apa.

Kami juga harus memodifikasi perpustakaan dengan file, ini bukan nilai tambah. Dan kelemahan signifikan lainnya - kami tidak memiliki kesempatan untuk membuka rantai layar di depan deeplink. Dalam hal aplikasi kita, kita ingin membuat tautan dalam ke keranjang, sebelum kita membuka semua layar sebelumnya: restoran, restoran tertentu, dan hanya setelah itu keranjang.

Juga, untuk bekerja dengan navigasi, Anda harus memiliki instance Lihat. Untuk mendapatkan navigator, Anda perlu membuka View - perpustakaan navigasi itu sendiri akan menghubungi orang tua dari View ini - dan mencoba untuk menemukan navigator di dalamnya. Jika dia menemukannya, maka layar menuju ke layar yang kita butuhkan.

Tetapi muncul pertanyaan: apakah layak menggunakan perpustakaan dalam pertempuran? Saya akan menjawab ya jika:



Jika kita perlu mendapatkan hasil yang cepat. Perpustakaan diimplementasikan dengan sangat cepat, dapat dimasukkan ke dalam proyek dalam waktu sekitar 20 menit, semua transisi ditusuk dengan mouse, semua ini nyaman. Itu juga ditulis dengan cepat dalam XML, cepat dirakit, dan cepat berfungsi. Semuanya super.

Jika Anda perlu memiliki banyak layar dalam aplikasi yang berfungsi dengan tautan dalam, dan tidak ada syarat untuk membuka.

Tidak ada aktivitas tunggal. Di sini, maksud saya bukan hanya Kegiatan tunggal. Kita dapat melakukan navigasi baik pada fragmen dengan satu aktivitas, dan pada campuran fragmen dan aktivitas, hanya dalam grafik Anda juga dapat menggambarkan aktivitas. Untuk ini, penyedia digunakan di dalam navigator, di mana ada dua implementasi navigasi. Satu pada Kegiatan, yang menciptakan Maksud untuk pergi ke Kegiatan yang diinginkan, implementasi kedua adalah navigator fragmen yang bekerja secara internal dengan manajer fragmen.

Jika Anda tidak memiliki logika kompleks untuk beralih antar layar. Setiap aplikasi unik dengan caranya sendiri, dan jika ada logika kompleks untuk membuka layar, perpustakaan ini bukan untuk Anda.

Anda siap masuk ke sumber dan memodifikasinya seperti yang kami lakukan. Ini sebenarnya sangat menarik.



Saya akan mengatakan tidak jika aplikasi memiliki logika navigasi yang rumit, jika Anda perlu membuka rantai layar sebelum deeplink, jika Anda memerlukan kondisi sulit untuk membuka layar melalui deeplink. Pada prinsipnya, dengan contoh otorisasi, ini bisa dilakukan, layar yang Anda butuhkan cukup terbuka, dan di atasnya adalah layar otorisasi. Jika pengguna tidak masuk, maka Anda dibuang ke tumpukan ke layar sebelumnya, sebelum layar rahasia dibuka. Keputusan kruk seperti itu.

Kehilangan tim sangat penting bagi Anda. Cicerone yang sama dapat menyimpan perintah ke buffer, dan ketika navigator menjadi tersedia, itu mengeksekusi mereka.

Jika Anda tidak memiliki keinginan untuk menyelesaikan kode, ini tidak berarti bahwa Anda sebagai pengembang tidak ingin melakukan sesuatu. Misalkan Anda memiliki tenggat waktu, manajer produk memberi tahu Anda bahwa Anda perlu memotong fitur, bisnis ingin mengeluarkan fitur. Anda memerlukan solusi turnkey yang berfungsi di luar kotak. Komponen Navigasi bukan tentang hal ini.

Satu hal lagi yang penting - DialogFragments tidak didukung. Seorang navigator yang akan bekerja dengan mereka dapat ditambahkan, tetapi karena alasan tertentu mereka tidak ditambahkan. Masalahnya adalah mereka sendiri terbuka sebagai fragmen biasa. Kotak centang untuk isShowing tidak diatur dan, karenanya, siklus hidup DialogFragments untuk membuat dialog tidak dijalankan. Bahkan, DialogFragment terbuka sebagai fragmen biasa, seluruh layar tanpa membuat jendela.

Itu semua untuk saya. Gali sumbernya, ini benar-benar menarik dan mengasyikkan. Berikut adalah bahan yang bermanfaat bagi mereka yang tertarik bekerja dengan perpustakaan navigasi. Terima kasih atas perhatian anda

Source: https://habr.com/ru/post/id455479/


All Articles