หน้านี้เป็นคู่มือสำหรับการแยกโค้ดการนำทางออกเป็นโมดูล ซึ่งมีวัตถุประสงค์เพื่อ เสริมแนวทางทั่วไปสำหรับการแยกแอปออกเป็นโมดูล
ภาพรวม
การแยกโค้ดการนำทางออกเป็นโมดูลคือกระบวนการแยกคีย์การนำทางที่เกี่ยวข้องและเนื้อหาที่คีย์เหล่านั้นแสดงออกเป็นโมดูลแต่ละโมดูล ซึ่งจะช่วยแยกความรับผิดชอบออกอย่างชัดเจนและช่วยให้คุณไปยังส่วนต่างๆ ระหว่างฟีเจอร์ต่างๆ ในแอปได้
หากต้องการแยกโค้ดการนำทางออกเป็นโมดูล ให้ทำดังนี้
- สร้างโมดูลย่อย 2 โมดูล ได้แก่
apiและimplสำหรับแต่ละฟีเจอร์ในแอป - วางคีย์การนำทางสำหรับแต่ละฟีเจอร์ลงในโมดูล
apiของฟีเจอร์นั้น - วาง
entryProvidersและเนื้อหาที่ไปยังส่วนต่างๆ ได้สำหรับแต่ละฟีเจอร์ลงในโมดูลimplที่เกี่ยวข้อง - ระบุ
entryProvidersให้กับโมดูลแอปหลัก ไม่ว่าจะโดยตรงหรือใช้การแทรกทรัพยากร Dependency
แยกฟีเจอร์ออกเป็นโมดูลย่อย api และ implementation
สร้างโมดูลย่อย 2 โมดูลชื่อ api และ impl (ย่อมาจาก "implementation") สำหรับแต่ละฟีเจอร์ในแอป ใช้ตารางต่อไปนี้เพื่อตัดสินใจว่าจะวางโค้ดการนำทางไว้ที่ใด
ชื่อโมดูล |
มี |
|
|
|
เนื้อหาสำหรับฟีเจอร์นั้น ซึ่งรวมถึงคำจำกัดความสำหรับ
|
แนวทางนี้ช่วยให้ฟีเจอร์หนึ่งไปยังส่วนต่างๆ ในอีกฟีเจอร์หนึ่งได้โดยอนุญาตให้เนื้อหาของฟีเจอร์หนึ่งซึ่งอยู่ในโมดูล impl ขึ้นอยู่กับคีย์การนำทางของอีกโมดูลหนึ่งซึ่งอยู่ในโมดูล api ของโมดูลนั้น
แยกรายการการนำทางโดยใช้ฟังก์ชันส่วนขยาย
ใน Navigation 3 ระบบจะกำหนดเนื้อหาที่ไปยังส่วนต่างๆ ได้ โดยใช้รายการการนำทาง หากต้องการ
แยกรายการเหล่านี้ออกเป็นโมดูลที่แยกกัน ให้สร้างฟังก์ชันส่วนขยายใน
EntryProviderScope แล้วย้ายฟังก์ชันเหล่านั้นไปยังโมดูล impl สำหรับฟีเจอร์นั้น
ซึ่งเรียกว่า ตัวสร้างรายการ
ตัวอย่างโค้ดต่อไปนี้แสดงเครื่องมือสร้างรายการที่สร้างรายการการนำทาง 2 รายการ
// 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 DSL เมื่อกำหนด
entryProvider ในโมดูลแอปหลัก
// import androidx.navigation3.runtime.entryProvider // import androidx.navigation3.ui.NavDisplay NavDisplay( entryProvider = entryProvider { featureAEntryBuilder() }, // ... )
ใช้การแทรกทรัพยากร Dependency เพื่อเพิ่มรายการลงในแอปหลัก
ในตัวอย่างโค้ดก่อนหน้า แอปหลักจะเรียกใช้ตัวสร้างรายการแต่ละรายการโดยตรงโดยใช้ DSL entryProvider หากแอปมีหน้าจอหรือโมดูลฟีเจอร์จำนวนมาก รูปแบบนี้อาจปรับขนาดได้ไม่ดี
หากต้องการแก้ปัญหานี้ ให้โมดูลฟีเจอร์แต่ละโมดูลมีส่วนร่วมในการสร้างรายการลงในกิจกรรมของแอปโดยใช้การแทรกการพึ่งพา
ตัวอย่างเช่น โค้ดต่อไปนี้ใช้ การผูกมัลติของ Dagger,
ซึ่งก็คือ @IntoSet เพื่อแทรกตัวสร้างรายการลงใน 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() } }, // ... ) } } }
หากรายการการนำทางต้องไปยังส่วนต่างๆ เช่น มีองค์ประกอบ UI ที่ไปยังส่วนต่างๆ ในหน้าจอใหม่ ให้แทรกออบเจ็กต์ที่สามารถแก้ไขสถานะการนำทางของแอปลงในฟังก์ชันตัวสร้างแต่ละฟังก์ชัน
แยกตัวจับคู่ Deep Link ออกเป็นโมดูล
หากแอปรองรับ Deep Link และแยกออกเป็นโมดูล โมดูลฟีเจอร์แต่ละโมดูล
ควรกำหนดอินสแตนซ์ DeepLinkMatcher สำหรับปลายทางที่เป็นเจ้าของ
หากต้องการรวบรวมตัวจับคู่ทั้งหมดจากทั่วทั้งแอป คุณสามารถใช้การผูกมัลติของการแทรกทรัพยากร Dependency ได้ ตัวอย่างเช่น โมดูลฟีเจอร์แต่ละโมดูลสามารถมีส่วนร่วมในการสร้างตัวจับคู่ลงในการผูกมัลติ 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) } } }
ดูข้อมูลเพิ่มเติมเกี่ยวกับการกำหนดและการจัดการ Deep Link ได้ที่หัวข้อการรองรับ Deep Link
แหล่งข้อมูล
ดูตัวอย่างโค้ดที่แสดงวิธีแยกโค้ด Navigation 3 ออกเป็นโมดูลได้ที่
- สูตรโค้ดสถาปัตยกรรม Navigation 3
- เส้นทางการเรียนรู้การแยกออกเป็นโมดูลจากแอป Now in Android
- Androidify