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