یکی از چالش های برنامه نویسی در اندروید زمانی هست که شما به صورت مالتی ماژول برنامه نویسی میکنید، در این حالت ممکن هست سر ایجاد یک سیستم Navigation به مشکل بر بخورید، چند مقاله در این مورد دیدم که مثلا در یکی از اون ها کلا بیخیال Navigation Component شده بودند و یک سیستم جدید برای خودشون درست کردند (که من نمیخواستم این کار رو بکنم)، بعضی هاشون کل سیستم نویگیشن رو به لایه App برده بودن (که به نظرم خیلی درست نیست) و بعضی هم کارهای دیگه . . .
در این مقاله با ایجاد یک ماژول جدا برای Navigation قراره یک سیستم برای این داستان درست کنیم .
توجه : من در حال درست کردن یک پروژه سمپل برای خودم هستم و این مشکل رو برخوردم، این مقاله بیشتر حالت ترجمه از این مقاله داره که هم کمی تغییرش دادم و یک سری چیزا بهش اضافه کردم
فرض کنید پروژه شما به این صورت باشه :
ما قراره از Search به Detail بریم و همین طور میتونیم از Saved هم به اون قسمت بریم، همچنین میشه بین Search و Saved با استفاده از نویگیشن باتن ها سوئیچ انجام داد
خب ما اینجا چند مورد رو باید هندل کنیم، یکی اتصال Navigation Button ها به Navigation Component یکی هم هندل Navigate بین ماژول های مختلف .
اول از همه که باید library های مورد نظر رو اضافه کنیم که نیاز به توضیح نداره و میتونید از این لینک استفاده کنید.
بعد از اون باید ببینیم معماری رو به چه صورت بچینیم، خب ما یک MainActivity رد لایه App خواهیم داشت که شامل FragmentContainerView و BottomNavigation هست :
اگر دقت کنید یک فایل نویگیشن گراف به اسم app_navigation به FragmentContainer الحاق شده، خب این کجاست ؟ این فایل و یک سری فایل مربوط به Navigation System در یک ماژول به نام Navigator (یا هر اسم دیگه که دوست دارید) وجود دارند :
یک گراف اصلی که app_navigation هست و یه گراف فرعی و یک nav_id که شامل یک سری id برای نویگیشن هستند، هدف این هست که یک سری nested graph در app_navigation داشته باشیم و هندل نویگیت بین ماژولی را با اون ها انجام بدیم، اول از همه nav_id رو ببینیم :
این Id ها از این به بعد در قسمت های مختلف استفاده خواهند شد و معرف nested graph های ما هستند، حالا فایل app_navigation رو با هم ببینیم :
که شمای گرافیکی اون به این صورت هست :
خب یک سری توضیحات باید بدم، همون طور که میبینید ما یک سری nested_graph در این فایل ایجاد کردیم که home رو هم saved_nav گذاشتیم، یک global action هم تعریف کردیم که کاربر از هرجا بخواهد بتواند به Detail برود (اکشن های گلوبال یعنی متکی به فرگمنت نیستند، از هر جا بخواهیم برویم به هر صفحه مورد نظر، میتونید این لینک رو ببینید)، تا اینجا چیز خاصی وجود نداشته، وقتشه بریم ببینیم این saved_nav یا detail_nav یا ... چی هستند، برای نمونه saved_nav :
خب این که خالیه :/ ولی مشکلی نداره ما عین همین فایل رو در ماژول Saved هم داریم که به این صورته :
الان چرا ما دو تا فایل تعریف کردیم ؟ و اینکه یکی اصلا چرا خالی بود، چند تا نکته اینجا هست، یکی اینکه ماژول Navigator متکی به هیچ ماژولی نیست ولی باقی ماژول ها متکی به اون هستند یعنی در داخل فایل gradle باید implementation رو انجام بدید :
implementation project(":navigator")
یک نکته رو در فهم این قضیه باید متوجه بشید و اونم اینه :
نکته اینه که ما در هیچ کدوم از این قسمت ها از + استفاده نکردیم، چرا ؟ چون همه این آیدی ها به همون فایل nav_id که ساخته بودیم اشاره دارن و دارن به این طریق با هم لینک میشن، یعنی درسته که ما یک فایل نویگیشن خالی در ماژول Navigator ساختیم ولی به مشکلی بر نمیخوریم چون در Run-Time این فایل به فایل اصلی که در داخل خود ماژول مثلا Saved هست به خاطر وجود Id یکسان لینک میشن !
یک خلاصه از کارایی که کردیم :
خب بریم سراغ بقیه چیزا، در ماژول Navigator اول از همه این Interface رو اضافه میکنیم :
این interface در MainActivity قرار داده میشه (Implement میشه) که یکم بعد بررسی میکنیم این رو، داخل این Interface یک NavigationFlow ورودی قرار داده شده :
این یک Sealed Class هست که متریال لازم برای هندل نویگت بین ماژولی رو درش قرار میدیم، یعنی مثلا اگه خواستیم بریم به صفحه Detail لازمه به Interface مون DetailFlow رو پاس بدیم .
نکته : به نظرم این فایل شاید کمی اصول SOLID رو نقض کنه، در واقع اصل O یعنی Open-Closed، چرا ؟ چون ما به ازای هر فیچر جدید شاید مجبوریم بشیم این فایل رو تغییر بدیم که درست نیست، میتونیم به جاش از وراثت استفاده کنیم یا ... .
یک فایل دیگر هم به اسم Navigator داریم که با استفاده از Sealed Class مون میاییم و مشخص میکنیم کدوم اکشن رو از نویگیشن گرافمون استفاده کنه :
در این فایل مثلا اگر DetailFlow بیاد میاد و اون اکشن گلوبالی که تو app_navigation بوده رو استفاده میکنه و در این مثال خاص دیتا هم داشته که به صورت bundle بشه پاس داده میشه .
خب حالا وقت استفاده از این فایل هاست که در MainActivity انجام میشه (ماژول App هم مثل Feature ها باید متکی به ماژول Navigator باشه و این ماژول در gradle اش اد بشه) :
خب خیلی هم خوب اما این تابع navigateToFlow چطور صدا زده بشه؟ اینجا تابع باید از سمت Fragment ها صدا زده بشن، برای اینکار میتویند یک BaseFragment ایجاد کنید که همه Fragment ها از اون ارث ببرن :
این طوری ما دسترسی به اون Interface رو در BaseFragment داریم، الان دیگه همه چیز حله، اگر بخوام میتونم مثلا از ماژول Saved به Detail برم :
و تمام ! فقط یک نکته میمونه و اون اتصال Navigation Button ها به Navigation Component هست، خب همون طور که میدونید Navigation Button ها یک فایل menu رو میگیرن :
آیدی که برای آیتم ها داده میشه باید مجددا همون آیدی باشه که در ماژول Navigator قرار دادیم، حالا یک تابع هست به این شکل :
bottomNav.setupWithNavController(navController)
و بعدش خود Navigation Componentبقیه شو انجام میده !!!
آدرس کانال تلگرامی ما : لینک
من رو در لینکدین ، اینستاگرام و یوتیوب دنبال کنید !!!
اگه دوست داشتید میتونید به صفحه Spotify و SoundCloud بنده هم برید و موسیقی های منو گوش بدید !!!