בדף הזה מוסבר איך להפוך את קוד הניווט למודולרי. הוא נועד להשלים את ההנחיות הכלליות בנושא מודולריזציה של אפליקציות.
סקירה כללית
הפיכת קוד הניווט למודולרי היא תהליך של הפרדת מקשי ניווט קשורים והתוכן שהם מייצגים למודולים נפרדים. כך יש הפרדה ברורה בין האחריות שלכם לבין האחריות שלנו, ואתם יכולים לנווט בין התכונות השונות באפליקציה.
כדי להפוך את קוד הניווט למודולרי:
- יוצרים שני מודולי משנה:
apiו-implלכל תכונה באפליקציה - ממקמים את מקשי הניווט של כל תכונה ב
apiהמודול שלה - ממקמים את
entryProvidersואת התוכן שניתן לנווט בו לכל תכונה במודולimplהמתאים. - מספקים
entryProvidersלמודולים העיקריים של האפליקציה, ישירות או באמצעות הזרקת תלות
הפרדה של התכונות למודולי משנה של API והטמעה
לכל תכונה באפליקציה, יוצרים שני מודולי משנה בשמות api ו-impl (קיצור של implementation, הטמעה). הטבלה הבאה תעזור לכם להחליט איפה למקם את קוד הניווט.
שם המודול |
מכיל |
|
|
|
תוכן לתכונה הזו, כולל הגדרות של |
הגישה הזו מאפשרת לתכונה אחת לנווט לתכונה אחרת על ידי כך שהתוכן שלה, שנמצא במודול impl שלה, תלוי במקשי הניווט של מודול אחר, שנמצא במודול api של אותו מודול.
הפרדה בין רשומות ניווט באמצעות פונקציות של תוספים
ב-Navigation 3, תוכן שאפשר לנווט בו מוגדר באמצעות רשומות ניווט. כדי להפריד בין הרשומות האלה למודולים נפרדים, צריך ליצור פונקציות של תוסף ב-EntryProviderScope ולהעביר אותן למודול impl של התכונה.
האפשרויות האלה נקראות כלי ליצירת רשומות.
בדוגמת הקוד הבאה מוצג כלי ליצירת רשומות שיוצר שתי רשומות ניווט.
// import androidx.navigation3.runtime.EntryProviderScope // import androidx.navigation3.runtime.NavKey fun EntryProviderScope<NavKey>.featureAEntryBuilder() { entry<KeyA> { ContentRed("Screen A") { // Content for screen A } } entry<KeyA2> { ContentGreen("Screen A2") { // Content for screen A2 } } }
מגדירים את entryProvider במודול הראשי של האפליקציה וקוראים לפונקציה באמצעות entryProvider DSL.
// import androidx.navigation3.runtime.entryProvider // import androidx.navigation3.ui.NavDisplay NavDisplay( entryProvider = entryProvider { featureAEntryBuilder() }, // ... )
שימוש בהזרקת תלות כדי להוסיף רשומות לאפליקציה הראשית
בדוגמת הקוד שלמעלה, כל כלי ליצירת רשומות נקרא ישירות על ידי האפליקציה הראשית באמצעות entryProvider DSL. אם באפליקציה יש הרבה מסכים או מודולים של תכונות, יכול להיות שהדפוס הזה לא יתאים.
כדי לפתור את הבעיה, צריך להגדיר שכל מודול של תכונות יתרום את בוני הרשומות שלו לפעילות של האפליקציה באמצעות הזרקת תלות.
לדוגמה, הקוד הבא משתמש בDagger multibindings, ובאופן ספציפי ב-@IntoSet, כדי להזריק את ה-entry builders ל-Set שבבעלות MainActivity. לאחר מכן, הפונקציות האלה מופעלות באופן איטרטיבי בתוך entryProvider, כך שלא צריך להפעיל במפורש פונקציות רבות של יצירת רשומות.
מודול של תכונות
// import dagger.Module // import dagger.Provides // import dagger.hilt.InstallIn // import dagger.hilt.android.components.ActivityRetainedComponent // import dagger.multibindings.IntoSet @Module @InstallIn(ActivityRetainedComponent::class) object FeatureAModule { @IntoSet @Provides fun provideFeatureAEntryBuilder() : EntryProviderScope<NavKey>.() -> Unit = { featureAEntryBuilder() } }
מודול אפליקציה
// import android.os.Bundle // import androidx.activity.ComponentActivity // import androidx.activity.compose.setContent // import androidx.navigation3.runtime.EntryProviderScope // import androidx.navigation3.runtime.NavKey // import androidx.navigation3.runtime.entryProvider // import androidx.navigation3.ui.NavDisplay // import javax.inject.Inject class MainActivity : ComponentActivity() { @Inject lateinit var entryBuilders: Set<@JvmSuppressWildcards EntryProviderScope<NavKey>.() -> Unit> override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) setContent { NavDisplay( entryProvider = entryProvider { entryBuilders.forEach { builder -> this.builder() } }, // ... ) } } }
אם רכיבי הניווט צריכים לנווט – למשל, אם הם מכילים רכיבי ממשק משתמש שמנווטים למסכים חדשים – צריך להחדיר אובייקט שיכול לשנות את מצב הניווט של האפליקציה לכל פונקציית Builder.
הפיכת התאמות של קישורי עומק למודולריות
אם האפליקציה שלכם תומכת בקישורי עומק והיא מודולרית, כל מודול תכונות צריך להגדיר את מופעי DeepLinkMatcher ליעדים שבבעלותו.
כדי לאסוף את כל רכיבי ההתאמה מכל האפליקציה, אפשר להשתמש ב-multibindings של הזרקת תלות. לדוגמה, כל מודול תכונות יכול לתרום את התאמים שלו ל-multibinding של Dagger @IntoSet:
מודול של תכונות
@Module @InstallIn(ActivityRetainedComponent::class) object FeatureADeepLinkModule { @IntoSet @Provides fun provideUserMatcher(): DeepLinkMatcher<*, *> { return UriDeepLinkMatcher( DeepLinkUri("www.example.com/users/{id}"), serializer<UserProfileKey>() ) } }
לאחר מכן, במודול האפליקציה הראשי, למשל ב-MainActivity, אפשר להוסיף את קבוצת ההתאמות ולהשתמש בהן כדי להתאים בקשות נכנסות:
מודול אפליקציה
@AndroidEntryPoint class MainActivityWithDI : ComponentActivity() { @Inject lateinit var deepLinkMatchers: Set<@JvmSuppressWildcards DeepLinkMatcher<*, *>> override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) val request = DeepLinkRequest(intent = intent) val matchResult = deepLinkMatchers .mapNotNull { it.match(request) } .maxOrNull() val backStack = when (matchResult) { null -> listOf(HomeKey) is BackStackMatchResult<*, *> -> { @Suppress("UNCHECKED_CAST") matchResult.backStack as List<NavKey> } else -> listOf(matchResult.key) } } }
מידע נוסף על הגדרה וטיפול בקישורי עומק זמין במאמר תמיכה בקישורי עומק.
משאבים
דוגמאות קוד שמראות איך להפוך את הקוד של Navigation 3 למודולרי:
- מתכוני קוד של ארכיטקטורת Navigation 3
- המדריך ללמידת מודולריזציה באפליקציית Now in Android
- Androidify