แยกโค้ดการนำทางออกเป็นโมดูล

หน้านี้เป็นคู่มือสำหรับการแยกโค้ดการนำทางออกเป็นโมดูล ซึ่งมีวัตถุประสงค์เพื่อ เสริมแนวทางทั่วไปสำหรับการแยกแอปออกเป็นโมดูล

ภาพรวม

การแยกโค้ดการนำทางออกเป็นโมดูลคือกระบวนการแยกคีย์การนำทางที่เกี่ยวข้องและเนื้อหาที่คีย์เหล่านั้นแสดงออกเป็นโมดูลแต่ละโมดูล ซึ่งจะช่วยแยกความรับผิดชอบออกอย่างชัดเจนและช่วยให้คุณไปยังส่วนต่างๆ ระหว่างฟีเจอร์ต่างๆ ในแอปได้

หากต้องการแยกโค้ดการนำทางออกเป็นโมดูล ให้ทำดังนี้

  • สร้างโมดูลย่อย 2 โมดูล ได้แก่ api และ impl สำหรับแต่ละฟีเจอร์ในแอป
  • วางคีย์การนำทางสำหรับแต่ละฟีเจอร์ลงในโมดูล api ของฟีเจอร์นั้น
  • วาง entryProviders และเนื้อหาที่ไปยังส่วนต่างๆ ได้สำหรับแต่ละฟีเจอร์ลงในโมดูล impl ที่เกี่ยวข้อง
  • ระบุ entryProviders ให้กับโมดูลแอปหลัก ไม่ว่าจะโดยตรงหรือใช้การแทรกทรัพยากร Dependency

แยกฟีเจอร์ออกเป็นโมดูลย่อย api และ implementation

สร้างโมดูลย่อย 2 โมดูลชื่อ api และ impl (ย่อมาจาก "implementation") สำหรับแต่ละฟีเจอร์ในแอป ใช้ตารางต่อไปนี้เพื่อตัดสินใจว่าจะวางโค้ดการนำทางไว้ที่ใด

ชื่อโมดูล

มี

api

คีย์การนำทาง

impl

เนื้อหาสำหรับฟีเจอร์นั้น ซึ่งรวมถึงคำจำกัดความสำหรับ NavEntrys และ entryProvider ดูเพิ่มเติมที่ การแก้ปัญหาคีย์กับเนื้อหา.

แนวทางนี้ช่วยให้ฟีเจอร์หนึ่งไปยังส่วนต่างๆ ในอีกฟีเจอร์หนึ่งได้โดยอนุญาตให้เนื้อหาของฟีเจอร์หนึ่งซึ่งอยู่ในโมดูล impl ขึ้นอยู่กับคีย์การนำทางของอีกโมดูลหนึ่งซึ่งอยู่ในโมดูล api ของโมดูลนั้น

แผนภาพการขึ้นต่อกันของโมดูลฟีเจอร์ที่แสดงวิธีที่โมดูล `impl` ขึ้นอยู่กับโมดูล `api`
รูปที่ 1 แผนภาพการพึ่งพาของโมดูลฟีเจอร์ที่แสดงวิธีที่โมดูล implementation สามารถขึ้นอยู่กับโมดูล 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 และแยกออกเป็นโมดูล โมดูลฟีเจอร์แต่ละโมดูล ควรกำหนดอินสแตนซ์ DeepLinkMatcher สำหรับปลายทางที่เป็นเจ้าของ

หากต้องการรวบรวมตัวจับคู่ทั้งหมดจากทั่วทั้งแอป คุณสามารถใช้การผูกมัลติของการแทรกทรัพยากร Dependency ได้ ตัวอย่างเช่น โมดูลฟีเจอร์แต่ละโมดูลสามารถมีส่วนร่วมในการสร้างตัวจับคู่ลงในการผูกมัลติ Dagger @IntoSet ได้ดังนี้

โมดูลฟีเจอร์

จากนั้นในโมดูลแอปหลัก เช่น ใน MainActivity คุณสามารถแทรกชุดตัวจับคู่และใช้ตัวจับคู่เหล่านั้นเพื่อจับคู่คำขอขาเข้าได้ดังนี้

โมดูลแอป

ดูข้อมูลเพิ่มเติมเกี่ยวกับการกำหนดและการจัดการ Deep Link ได้ที่หัวข้อการรองรับ Deep Link

แหล่งข้อมูล

ดูตัวอย่างโค้ดที่แสดงวิธีแยกโค้ด Navigation 3 ออกเป็นโมดูลได้ที่