Membuat kode navigasi modular

Halaman ini adalah panduan untuk memodularisasi kode navigasi Anda. Tujuannya adalah untuk melengkapi panduan umum modularisasi aplikasi.

Ringkasan

Modularisasi kode navigasi adalah proses pemisahan kunci navigasi terkait, dan konten yang diwakilinya, ke dalam modul terpisah. Hal ini memberikan pemisahan tanggung jawab yang jelas dan memungkinkan Anda berpindah-pindah antara berbagai fitur di aplikasi.

Untuk memodularisasi kode navigasi Anda, lakukan hal berikut:

  • Buat dua submodul: api dan impl untuk setiap fitur di aplikasi Anda
  • Tempatkan tombol navigasi untuk setiap fitur ke dalam modul api-nya
  • Tempatkan entryProviders dan konten yang dapat dijelajahi untuk setiap fitur ke dalam modul impl terkait
  • Sediakan entryProviders ke modul aplikasi utama Anda, baik secara langsung maupun menggunakan injeksi dependensi

Memisahkan fitur ke dalam submodul API dan implementasi

Untuk setiap fitur di aplikasi Anda, buat dua submodule bernama api dan impl (singkatan dari "implementasi"). Gunakan tabel berikut untuk memutuskan tempat menempatkan kode navigasi.

Nama modul

Berisi

api

tombol navigasi

impl

Konten untuk fitur tersebut, termasuk definisi untuk NavEntry dan entryProvider. Lihat juga menyelesaikan kunci ke konten.

Pendekatan ini memungkinkan satu fitur menavigasi ke fitur lain dengan mengizinkan kontennya, yang ada dalam modul impl, bergantung pada tombol navigasi modul lain, yang ada dalam modul api modul tersebut.

Diagram dependensi modul fitur yang menunjukkan cara modul `impl` dapat bergantung pada modul `api`.
Gambar 1. Diagram dependensi modul fitur yang menunjukkan cara modul implementasi dapat bergantung pada modul API.

Memisahkan entri navigasi menggunakan fungsi ekstensi

Di Navigation 3, konten yang dapat dijelajahi ditentukan menggunakan entri navigasi. Untuk memisahkan entri ini ke dalam modul terpisah, buat fungsi ekstensi di EntryProviderScope dan pindahkan ke modul impl untuk fitur tersebut. Fitur ini dikenal sebagai pembuat entri.

Contoh kode berikut menunjukkan pembuat entri yang membuat dua entri navigasi.

// 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
        }
    }
}

Panggil fungsi tersebut menggunakan DSL entryProvider saat menentukan entryProvider di modul aplikasi utama.

// import androidx.navigation3.runtime.entryProvider
// import androidx.navigation3.ui.NavDisplay
NavDisplay(
    entryProvider = entryProvider {
        featureAEntryBuilder()
    },
    // ...
)

Menggunakan injeksi dependensi untuk menambahkan entri ke aplikasi utama

Dalam contoh kode sebelumnya, setiap builder entri dipanggil langsung oleh aplikasi utama menggunakan DSL entryProvider. Jika aplikasi Anda memiliki banyak layar atau modul fitur, pola ini mungkin tidak dapat diskalakan dengan baik.

Untuk mengatasinya, setiap modul fitur harus memberikan builder entri ke aktivitas aplikasi menggunakan injeksi dependensi.

Misalnya, kode berikut menggunakan multi-binding Dagger, khususnya @IntoSet, untuk menyuntikkan builder entri ke Set yang dimiliki oleh MainActivity. Kemudian, fungsi ini dipanggil secara iteratif di dalam entryProvider, sehingga tidak perlu memanggil banyak fungsi builder entri secara eksplisit.

Modul fitur

// 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()
    }
}

Modul aplikasi

// 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() }
                },
                // ...
            )
        }
    }
}

Jika entri navigasi Anda perlu melakukan navigasi—misalnya, entri tersebut berisi elemen UI yang melakukan navigasi ke layar baru—suntikkan objek yang dapat mengubah status navigasi aplikasi ke setiap fungsi builder.

Jika aplikasi Anda mendukung deep link dan dimodularisasi, setiap modul fitur harus menentukan instance DeepLinkMatcher untuk tujuan yang dimilikinya.

Untuk mengumpulkan semua pencocokan dari seluruh aplikasi, Anda dapat menggunakan multibinding injeksi dependensi. Misalnya, setiap modul fitur dapat memberikan pencocoknya ke multibinding Dagger @IntoSet:

Modul fitur

Kemudian, di modul aplikasi utama, seperti di MainActivity, Anda dapat menyuntikkan kumpulan pencocok dan menggunakannya untuk mencocokkan permintaan yang masuk:

Modul aplikasi

Untuk mengetahui informasi selengkapnya tentang cara menentukan dan menangani deep link, lihat Mendukung deep link.

Resource

Untuk contoh kode yang menunjukkan cara memodularisasi kode Navigation 3, lihat: