رویکرد جدید؛ یک اکتیویتی برای هر اپلیکیشن کافیه! (۱)

مسیریابی با Navigation Componentمسیریابی بین فرگمنت و اکتیویتی ها در اندروید می تونه برای یک برنامه نویس تازه کار پیچیده به نظر برسه. مسائل زیادی وجود داره که باید فکری به حالش کرد. از انتقال داده گرفته تا اضافه کردن انیمیشن، کنترل بک اِستَک و بسیاری مسائل دیگه که باید مدیریت بشن.برای ساده شدن این فرآیند و رسیدن به یک رویکرد جدید، گوگل درکنفرانس I/O سال گذشته با معرفی ابزار Navigation Component، رویکرد Single Activity Per Application (یک اکتیویتی برای هر اپلیکیشن) رو به عنوان رویکرد مورد استاندارد خودش اعلام کرد. سعی می کنم در این مقاله ابزار Navigation رو به طور کامل معرفی و پیاده سازی کنم.هدف ابزار Navigation ساده شدن جابجایی بین صفحات مختلف یک برنامه است. اگه میخواهید بدونید چقدر ساده باید بگم به سادگی همین تصویر بالا...این عکس تصویری از اصلی ترین فایل کتابخانه Navigation هست که به صورت گرافیکی همه سیاست های مسیریابی یک اپلیکیشن در آن نشون داده میشه. مثلا اینکه چه فرگمنتی به کدام فرگمنت دیگه مسیر داره، چه انیمیشینی در زمان انتقال اجرا میشه، چه مقادیری در یک انتقال باید جابجا بشه و خیلی چیزهای دیگه.به این فایل Navigation Graph (گراف مسیریابی) میگیم که بعدا مفصل راجع بهش حرف می زنیم. فعلا همین قدر بدونید که روال کار به همین سادگیه. یه جا سیاست های انتقال نوشته می شه. بعد با یکی دو خط کد نویسی این سیاست ها را فراخوانی و اجرا می کنیم.نکته مهم: برای کار با کتابخانه Navigation حتما باید از اندروید استودیو نسخه 3.3 (یا بالاتر) و پروژه androidx استفاده کنید.لینک پروژه این مقاله: https://github.com/itsamirrezah/SimpleNavigationComponent اضافه شدن کتابخانه به پروژه:برای اضافه شدن کتابخانه Navigation، تکه کد زیر را به فایل build.gradle (در ماژول app) اضافه کنید: https://gist.github.com/itsamirrezah/cee551afc0cef913717884b0d2f70b9f مفاهیم اصلی برای کار با NavigationNavigation Graph:یک فایل ساده xml است که سیاست های نحوه جابجا شدن صفحات مختلف برنامه رو مشخص می کنه.Destination:هر صفحه از یه اپلیکیشن (فرگمنت یا اکتیویتی)، در فایل گراف مسیریابی به عنوان یک Destination معرفی میشن.Action:به فرآیند انتقال از یک Destination به Destination دیگه Action میگیم.NavHost:هر Destination برای اینکه بتونه به نمایش دربیاد نیاز به یک "قاب" و "فریم" داره. به این قاب NavHost میگیم.NavController:وظیفه تعویض تصاویر (یا همون Destination) روی قاب NavHost به عهده شی NavController هست.حالا می تونیم شروع به کار کنیم. به عنوان اولین تلاش یه پروژه ساده رو پیاده می کنیم که با کمک کتابخانه Navigation از یک فرگمنت به فرگمنت دیگه منتقل بشیم. برنامه ما یک اکتیویتی و دو فرگمنت با نام های FragA و FragB داره که وقتی برنامه اجرا میشه FragA به صورت پیشفرض نمایش داده میشه. با کلیک بر روی یک Button برنامه به FragB منتقل میشه. از اکتیویتی هم فقط به عنوان نقطه شروع برنامه استفاده می کنیم و بعد از اون دیگه باهاش کاری نداریم.به طور خلاصه لیستی از کارهایی که باید انجام بدیم:ایجاد فایل گراف مسیریابی (Navigation Graph)معرفی NavHost به گراف مسیریابیمعرفی Destination ها به گراف مسیریابیمعرفی یک action برای انتقال از فرگمنت A به فرگمنت Bاستفاده از شی NavController برای دسترسی به action ساخته شده و نهایی کردن انتقالایجاد فایل گراف مسیریابیبرای شروع باید فایل گراف مسیریابی یا همون Navigation Graph رو بسازیم. همانطور که گفتیم گراف مسیریابی چیزی جز یه فایل ساده xml نیست. برای ساختن این فایل بر روی فولدر res کلیک راست کنین و گزینه New>Android Resource File رو انتخاب کنید.حالا در پنجره New Resource File، یک نام اختیاری برای گرافتون انتخاب کنید و Resource Type رو هم بر روی Navigation قرار بدید.ایجاد گراف مسیریابی حالا گراف مسیریابی ساخته شده و از مسیر res>navigation>navigation_graph.xml قابل دسترسی است.شناسایی NavHost به گراف مسیریابیگراف مسیریابی دو تب داره که تب Design برای نمایش گرافیکی مسیریابی ها و تب Text برای نمایش کد های xml مسیریابی ها است. اگر از تب Design فایل رو باز کنید در قسمت Destination، دو بخش Host و Graph رو می بینین.در بخش Host، NavHost ها قرار میگیرن. (همون قاب تو خالی که به Destination ها اجازه نمایش میده.) و در بخش Graph، Destination های برنامه قرار میگیرن.برای اینکه گراف مسیریابی NavHost شما رو بشناسه باید اون رو در فایل "لایه" Activity (مثلا فایل activity_main.xml) معرفی کنین. معمولا از تگ <fragment> به عنوان NavHost استفاده میشه.شبیه به تکه کد زیر: https://gist.github.com/itsamirrezah/1f81f36b7f5fae5a99e88a23320634ad بررسی ویژگی های مهم: name:اگر این ویژگی با مقدار “android.navigation.fragment.NavHostFragment” مقدار دهی شود این تگ <fragment> به عنوان NavHost به گراف مسیریابی شناخته میشه.navGraph:با کمک این ویژگی NavHost متوجه میشه که باید از سیاست های کدام گراف مسیریابی پیروی کند.defaultNavHost:مقدار این ویژگی به عملکرد کلید Back مرتبطه. اگه مقدار آن False باشه هر موقعی که کاربر کلید Back را فشار بده از برنامه خارج می شود. ولی در صورت True بودن، با فشردن کلید Back برنامه به صفحه قبل از خودش برمیگرده. اینکار انقدر تکرار میشه تا زمانی که به صفحه ابتدایی برنامه برسه و در نهایت از برنامه خارج بشه. با اعمال این تغییرات به گراف مسیریابی برمیگردیم و میبینیم NavHost ما به طور خودکار شناخت شده.شناسایی NavHost به گراف مسیریابی معرفی Destination به گراف مسیریابیخب زمان معرفی Destination ها به گراف مسیریابی است. گفتیم صفحات برنامه (مثل فرگمنت یا اکتیویتی ها) را در گراف مسیریابی به عنوان Destination میشناسیم. برای اینکار فایل گراف مسیریابی و در حالت Design قرار میدیم و تغییرات لازم رو ایجاد می کنیم.برای معرفی یک Destination بر روی آیکون New Destination کلیک کنید. حالا لیستی از صفحات برنامه لود می شود. چند فرگمنت به دلخواه به گراف مسیریابی اضافه کنید.اضافه کردن Destination به گراف مسیریابی ویژگی های مهم Destination:id:برای انتقال بین Destination های مختلف از آیدی استفاده میشه. این آیدی فقط مربوط به جابجایی و عملیات انتقال هست و با آیدی لایه فرگمنت ارتباطی نداره.name:این ویژگی ارتباط بین Destination در گراف مسیریابی با فایل اصلی فرگمنت رو (که به زبان جاوا یا کاتلین نوشته شده) برقرار میکنه. مثلا اگه فایل فرگمنت با نام FragA در پکیج Ui وجود داشته باشه به شکل زیر name مقدار دهی میشه: نام_پکیج_پروژه.Ui.FragAخب Destination ها به گراف معرفی شدن و فقط باید مشخص بشه کدوم Destination به عنوان صفحه شروع برنامه انتخاب بشه. برای اینکار باید از ویژگی StartDestination در تگ ریشه <navigation> استفاده کنیم. آیدی یکی از Destination ها باید به عنوان مقدار این ویژگی تعیین شه. در این مثال FragA به عنوان صفحه شروع انتخاب شد. https://gist.github.com/itsamirrezah/cf3c9a68ac4666e99e0f7e2ce273c350 حالا با اجرای برنامه FragA نمایش داده میشه ولی هنوز خبری از FragB نیست، چون هنوز عمل انتقال از FragA به FragB رو انجام ندادیم. برای شروع یه Button در لایه FragA می سازیم تا بتونیم با کلیک روی اون به FragB منتقل شیم.معرفی actionبرای اینکه انتقال از یک فرگمنت به فرگمنت دیگه کامل شه نیاز به استفاده از تگ <action> داریم. تگ های action هم در گراف مسیریابی معرفی و نگهداری می شوند. و درون آنها اطلاعات انتقال قرار میگیره. منظور از اطلاعات انتقال چیزهایی مثل آدرس Destination مقصد، انیمیشن و داده های ارسالی در هنگام انتقال و ... هست. تگ action باید درون تگ Destination مبدا قرار بگیره، به این صورت مبدا انتقال مشخص میشه. هر action ویژگی های زیر دارد:id:هر action باید یک آیدی منحصر به فرد داشته باشه تا در مرحله بعد با کمک شی NavController به آن دسترسی پیدا کنیم.destination: آدرس Destination مقصد را مشخص میکنه. مقدار این ویژگی آیدی یکی از Destination ها است که در گراف مسیریابی قبلا معرفی شد https://gist.github.com/itsamirrezah/d0b86de860b7da8aaf1cda50383ef388 تکمیل انتقال با کمک شی NavController:خب کار ما با گراف مسیریابی تمام شد و حالا تنها کار باقی مونده دسترسی به action ساخته شده و اجرای عملیات انتقال است. برای اینکار از شی NavController استفاده می کنیم. از NavController برای انتقال از یک Destination به یک Destination دیگه استفاده میشه.با استفاده از دستور ()Navigation.findNavController میشه به NavController دسترسی پیدا کرد. توجه کنید که متد findNavController نیاز به یک View به عنوان ورودی داره. این View باید به هر شکلی جزئی از Destination مبدا باشه. مثلا Viewی ریشه یک فرگمنت یا یکی از ویجت های استفاده شده در فرگمنت. دسترسی به NavController کامل شده حالا با استفاده از متد ()navigate عملیات جابجایی بین فرگمنت ها رو کامل می کنیم. این متد یک آیدی به عنوان ورودی میگیره و این آیدی یا باید آیدی Destination مقصد باشه یا آیدی یک action. هر دو روش کار میکنه ولی پیشنهاد می کنم همیشه از action استفاده کنید، چون قدرت کنترل اطلاعات بیشتری دارند. (انتقال داده، تغییر انیمیشن و ..) https://gist.github.com/itsamirrezah/7c705e9fd0e3aff55631662d3232a4c5 حالا با کلیک روی button در FragmentA به صفحه FragmentB منتقل می شید.تغییر انیمیشن انتقالگفتیم که یکی از فایده های کار با action کنترل انیمیشن انتقال صفحه هست. کنترل انیمیشن با action خیلی خیلی آسونه. فقط کافیه از ویژگی های exitAnim و enterAnim استفاده کنید. https://gist.github.com/itsamirrezah/48a0a962fe0e66a82c381e142c7d68e1 exitAnim: انیمیشنی که در زمان خارج شدن از صفحه مبدا نمایش داده میشه.enterAnim:انیمیشنی که در زمان ورود به صفحه مقصد نمایش داده میشه.همین! مابقی کارها رو Navigation کنترل می کنه!