کتابخانه Dynamic Navigator عملکرد مؤلفه Jetpack Navigation را گسترش میدهد تا با مقصدهایی که در واحدهای ویژگی تعریف شدهاند کار کند. این کتابخانه همچنین نصب یکپارچه واحدهای ویژگی درخواستی را هنگام پیمایش به این مقصدها فراهم میکند.
راهاندازی
برای پشتیبانی از واحدهای ویژگی، از وابستگیهای زیر در فایل build.gradle واحد برنامهتان استفاده کنید:
گرووی
dependencies { def nav_version = "2.10.2" api "androidx.navigation:navigation-fragment-ktx:$nav_version" api "androidx.navigation:navigation-ui-ktx:$nav_version" api "androidx.navigation:navigation-dynamic-features-fragment:$nav_version" }
کاتلین
dependencies { val nav_version = "2.10.2" api("androidx.navigation:navigation-fragment-ktx:$nav_version") api("androidx.navigation:navigation-ui-ktx:$nav_version") api("androidx.navigation:navigation-dynamic-features-fragment:$nav_version") }
توجه داشته باشید که سایر وابستگیهای Navigation باید از پیکربندیهای api استفاده کنند تا برای واحدهای ویژگی شما دردسترس باشند.
استفاده پایه
برای پشتیبانی از واحدهای ویژگی، ابتدا همه نمونههای
NavHostFragment را در برنامهتان به
androidx.navigation.dynamicfeatures.fragment.DynamicNavHostFragment تغییر دهید:
<androidx.fragment.app.FragmentContainerView
android:id="@+id/nav_host_fragment"
android:name="androidx.navigation.dynamicfeatures.fragment.DynamicNavHostFragment"
app:navGraph="@navigation/nav_graph"
... />
سپس، مشخصه app:moduleName را به هر مقصد <activity>، <fragment>، یا
<navigation> در نمودارهای پیمایش واحد com.android.dynamic-feature که با DynamicNavHostFragment مرتبط است اضافه کنید.
این مشخصه به کتابخانه Dynamic Navigator میگوید که مقصد
به واحد ویژگی با نامی که مشخص میکنید تعلق دارد.
<fragment
app:moduleName="myDynamicFeature"
android:id="@+id/featureFragment"
android:name="com.google.android.samples.feature.FeatureFragment"
... />
وقتی به یکی از این مقصدها پیمایش میکنید، کتابخانه Dynamic Navigator ابتدا بررسی میکند که واحد ویژگی نصب شده است یا نه. اگر واحد ویژگی ازقبل وجود داشته باشد، برنامهتان طبق انتظار به مقصد پیمایش میکند. اگر ماژول وجود نداشته باشد، برنامهتان هنگام نصب ماژول، مقصد قطعه پیشرفت میانی را نشان میدهد. پیادهسازی پیشفرض تکه پیشرفت، میانای کاربری پایهای را با نوار پیشرفت نشان میدهد و هرگونه خطای نصب را مدیریت میکند.
برای سفارشیسازی این میانای کاربر، یا برای مدیریت دستی پیشرفت نصب از داخل صفحه برنامه خودتان، بخشهای سفارشیسازی قطعه پیشرفت و پایش وضعیت درخواست را در این موضوع ببینید.
مقصدهایی که app:moduleName را مشخص نمیکنند همچنان بدون تغییر کار میکنند و طوری رفتار میکنند که گویی برنامه شما از NavHostFragment معمولی استفاده میکند.
سفارشیسازی قطعه پیشرفت
میتوانید پیادهسازی قطعه پیشرفت را برای هر نمودار پیمایش لغو کنید
با تنظیم کردن ویژگی app:progressDestination روی شناسه مقصدی
که میخواهید برای رسیدگی به پیشرفت نصب استفاده کنید. مقصد پیشرفت سفارشی شما باید
Fragment باشد که از
AbstractProgressFragment مشتق شده است.
باید روشهای انتزاعی را برای اعلانهای مربوط به پیشرفت نصب، خطاها، و رویدادهای دیگر لغو کنید. سپس میتوانید پیشرفت نصب را در
رابط کاربری انتخابیتان نشان دهید.
کلاس
DefaultProgressFragment
پیادهسازی پیشفرض از این میانای برنامهسازی کاربردی برای نشان دادن پیشرفت نصب استفاده میکند.
پایش کردن وضعیت درخواست
کتابخانه Dynamic Navigator به شما امکان میدهد جریان تجربه کاربری مشابه با جریان موجود در روالهای مطلوب تجربه کاربری برای تحویل درخواستی را پیادهسازی کنید، که در آن کاربر درحین انتظار برای تکمیل نصب، در بافت صفحه قبلی باقی میماند. این یعنی اصلاً لازم نیست واسط کاربری میانی یا قطعه پیشرفت را نشان دهید.
در این سناریو، شما مسئول نظارت و رسیدگی به همه وضعیتهای نصب، تغییرات پیشرفت، خطاها، و غیره هستید.
برای شروع این جریان پیمایش غیرمسدودکننده، یک شیء
DynamicExtras
را که حاوی یک
DynamicInstallMonitor
است به
NavController.navigate()
ارسال کنید، همانطور که در مثال زیر نشان داده شده است:
کاتلین
val navController = ... val installMonitor = DynamicInstallMonitor() navController.navigate( destinationId, null, null, DynamicExtras(installMonitor) )
جاوا
NavController navController = ... DynamicInstallMonitor installMonitor = new DynamicInstallMonitor(); navController.navigate( destinationId, null, null, new DynamicExtras(installMonitor); )
بلافاصله پساز فراخوانی navigate()، باید مقدار
installMonitor.isInstallRequired را بررسی کنید تا ببینید آیا پیمایش انجامشده منجر به
نصب واحد ویژگی شده است یا نه.
- اگر مقدار
falseباشد، به مقصد عادی پیمایش میکنید و لازم نیست کار دیگری انجام دهید. اگر مقدار
trueاست، باید شروع به مشاهده شیءLiveDataکنید که اکنون درinstallMonitor.statusاست. این شیءLiveDataSplitInstallSessionStateبهروزرسانیها را از کتابخانه «هسته Play» منتشر میکند. این بهروزرسانیها حاوی رویدادهای پیشرفت نصب هستند که میتوانید از آنها برای بهروزرسانی میانای کاربر استفاده کنید. بهخاطر داشته باشید که همه وضعیتهای مربوطه را همانطور که در راهنمای Play Core ذکر شده است، ازجمله درخواست تأیید کاربر درصورت لزوم، مدیریت کنید.کاتلین
val navController = ... val installMonitor = DynamicInstallMonitor() navController.navigate( destinationId, null, null, DynamicExtras(installMonitor) ) if (installMonitor.isInstallRequired) { installMonitor.status.observe(this, object : Observer<SplitInstallSessionState> { override fun onChanged(sessionState: SplitInstallSessionState) { when (sessionState.status()) { SplitInstallSessionStatus.INSTALLED -> { // Call navigate again here or after user taps again in the UI: // navController.navigate(destinationId, destinationArgs, null, null) } SplitInstallSessionStatus.REQUIRES_USER_CONFIRMATION -> { SplitInstallManager.startConfirmationDialogForResult(...) } // Handle all remaining states: SplitInstallSessionStatus.FAILED -> {} SplitInstallSessionStatus.CANCELED -> {} } if (sessionState.hasTerminalStatus()) { installMonitor.status.removeObserver(this); } } }); }
جاوا
NavController navController = ... DynamicInstallMonitor installMonitor = new DynamicInstallMonitor(); navController.navigate( destinationId, null, null, new DynamicExtras(installMonitor); ) if (installMonitor.isInstallRequired()) { installMonitor.getStatus().observe(this, new Observer<SplitInstallSessionState>() { @Override public void onChanged(SplitInstallSessionState sessionState) { switch (sessionState.status()) { case SplitInstallSessionStatus.INSTALLED: // Call navigate again here or after user taps again in the UI: // navController.navigate(mDestinationId, mDestinationArgs, null, null); break; case SplitInstallSessionStatus.REQUIRES_USER_CONFIRMATION: SplitInstallManager.startConfirmationDialogForResult(...) break; // Handle all remaining states: case SplitInstallSessionStatus.FAILED: break; case SplitInstallSessionStatus.CANCELED: break; } if (sessionState.hasTerminalStatus()) { installMonitor.getStatus().removeObserver(this); } } }); }
وقتی نصب بهپایان میرسد، شیء LiveData وضعیت SplitInstallSessionStatus.INSTALLED را صادر میکند. سپس باید دوباره با
NavController.navigate() تماس بگیرید. چون اکنون ماژول نصب شده است، فراخوانی
اکنون موفقیتآمیز است و برنامه طبق انتظار به مقصد پیمایش میکند.
پساز رسیدن به وضعیت پایانی، مثلاً وقتی نصب تکمیل میشود یا وقتی نصب ناموفق است، باید LiveData observer را بردارید تا از نشت حافظه جلوگیری شود. بااستفاده از SplitInstallSessionStatus.hasTerminalStatus() میتوانید بررسی کنید که آیا وضعیت نشاندهنده حالت پایانه است یا نه.
برای نمونهای از پیادهسازی این ناظر،
AbstractProgressFragment را ببینید.
نمودارهای موجود
کتابخانه Dynamic Navigator از گنجاندن نمودارهایی که در واحدهای ویژگی تعریف شدهاند پشتیبانی میکند. برای گنجاندن نموداری که در واحد ویژگی تعریف شده است، کارهای زیر را انجام دهید:
بهجای
<include/>از<include-dynamic/>استفاده کنید، همانطور که در مثال زیر نشان داده شده است:<include-dynamic android:id="@+id/includedGraph" app:moduleName="includedgraphfeature" app:graphResName="included_feature_nav" app:graphPackage="com.google.android.samples.dynamic_navigator.included_graph_feature" />در
<include-dynamic ... />، باید مشخصههای زیر را مشخص کنید:app:graphResName: نام فایل منبع نمودار پیمایش. نام از نام فایل نمودار گرفته شده است. برای مثال، اگر نمودار درres/navigation/nav_graph.xmlباشد، نام منبعnav_graphاست.android:id- شناسه مقصد نمودار. کتابخانه Dynamic Navigator هرگونه مقدارandroid:idرا که در عنصر ریشه نمودار گنجاندهشده پیدا شود نادیده میگیرد.-
app:moduleName: نام بسته واحد.
از graphPackage صحیح استفاده کنید
مهم است که app:graphPackage را درست وارد کنید، زیرا درغیراینصورت مؤلفه «پیمایش» نمیتواند navGraph مشخصشده را از واحد ویژگی اضافه کند.
نام بسته واحد ویژگی پویا با افزودن نام واحد به applicationId واحد برنامه پایه ساخته میشود. بنابراین اگر
واحد برنامه پایه دارای applicationId com.example.dynamicfeatureapp باشد و
نام واحد ویژگی پویا DynamicFeatureModule باشد، نام بسته
واحد پویا
com.example.dynamicfeatureapp.DynamicFeatureModule خواهد بود. این نام بسته
حروفحساس است.
اگر شک دارید، میتوانید نام بسته واحد ویژگی را با بررسی AndroidManifest.xml تولیدشده تأیید کنید. پساز ساختن پروژه، به
<DynamicFeatureModule>/build/intermediates/merged_manifest/debug/AndroidManifest.xml بروید،
که باید چیزی شبیه به این باشد:
<manifest xmlns:android="http://schemas.android.com/apk/res/android" xmlns:dist="http://schemas.android.com/apk/distribution" featureSplit="DynamicFeatureModule" package="com.example.dynamicfeatureapp" android:versionCode="1" android:versionName="1.0" > <uses-sdk android:minSdkVersion="21" android:targetSdkVersion="30" /> <dist:module dist:instant="false" dist:title="@string/title_dynamicfeaturemodule" > <dist:delivery> <dist:install-time /> </dist:delivery> <dist:fusing dist:include="true" /> </dist:module> <application /> </manifest>
مقدار featureSplit باید با نام واحد ویژگی پویا مطابقت داشته باشد و بسته با applicationId واحد برنامه پایه مطابقت خواهد داشت. app:graphPackage ترکیبی از این موارد است: com.example.dynamicfeatureapp.DynamicFeatureModule.
پیمایش به نمودار ناوبری include-dynamic
فقط میتوان به startDestination از
include-dynamic نمودار ناوبری پیمایش کرد. واحد پویا مسئول نمودار ناوبری خودش است و برنامه پایه هیچ اطلاعی از آن ندارد.
سازوکار include-dynamic به ماژول برنامه پایه امکان میدهد تا
نمودار ناوبری تودرتو
را که در ماژول پویا تعریف شده است، شامل شود. این گراف ناوبری تودرتو مانند هر گراف ناوبری تودرتوی دیگری رفتار میکند. نمودار پیمایش ریشه (یعنی والد
نمودار تودرتو) فقط میتواند خود نمودار پیمایش تودرتو را بهعنوان
مقصد تعریف کند و نه فرزندان آن را. بنابراین، وقتی گراف include-dynamicnavigation مقصد باشد، از startDestination استفاده میشود.
محدودیتها
- درحالحاضر نمودارهای گنجاندهشده بهصورت پویا از پیوندهای عمیق پشتیبانی نمیکنند.
- نمودارهای تودرتوی بارشده بهصورت پویا (یعنی عنصر
<navigation>باapp:moduleName) درحالحاضر از پیوندهای عمیق پشتیبانی نمیکنند.