Esta página es una guía para modularizar tu código de navegación. Su objetivo es complementar la guía general para la modularización de apps.
Descripción general
Modularizar tu código de navegación es el proceso de separar las claves de navegación relacionadas y el contenido que representan en módulos individuales. Esto proporciona una separación clara de responsabilidades y te permite navegar entre diferentes funciones de tu app.
Para modularizar tu código de navegación, haz lo siguiente:
- Crea dos submódulos:
apiyimplpara cada función de tu app. - Coloca las claves de navegación de cada función en su módulo
api. - Coloca
entryProvidersy el contenido navegable de cada función en el móduloimplasociado. - Proporciona
entryProvidersa los módulos principales de tu app, ya sea directamente o con la inserción de dependencias.
Separa las funciones en submódulos de API y de implementación
Para cada función de tu app, crea dos submódulos llamados api y impl (abreviatura de "implementación"). Usa la siguiente tabla para decidir dónde colocar el código de navegación.
Nombre del módulo |
Contiene |
|
|
|
Es el contenido de esa función, incluidas las definiciones de los |
Este enfoque permite que una función navegue a otra, ya que su contenido, incluido en su módulo impl, depende de las claves de navegación de otro módulo, incluido en el módulo api de ese módulo.
Cómo separar las entradas de navegación con funciones de extensión
En Navigation 3, el contenido navegable se define con entradas de navegación. Para separar estas entradas en módulos independientes, crea funciones de extensión en EntryProviderScope y muévelas al módulo impl de esa función.
Estos se conocen como creadores de entradas.
En el siguiente ejemplo de código, se muestra un compilador de entradas que crea dos entradas de navegación.
// 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 } } }
Llama a esa función con el DSL de entryProvider cuando definas tu entryProvider en el módulo principal de la app.
// import androidx.navigation3.runtime.entryProvider // import androidx.navigation3.ui.NavDisplay NavDisplay( entryProvider = entryProvider { featureAEntryBuilder() }, // ... )
Usa la inserción de dependencias para agregar entradas a la app principal
En el ejemplo de código anterior, la app principal llama directamente a cada compilador de entradas con el DSL de entryProvider. Si tu app tiene muchas pantallas o módulos de funciones, es posible que este patrón no se ajuste bien.
Para resolver este problema, haz que cada módulo de funciones aporte sus compiladores de entradas a la actividad de la app con la inserción de dependencias.
Por ejemplo, el siguiente código usa vinculaciones múltiples de Dagger, específicamente @IntoSet, para insertar los compiladores de entradas en un Set que pertenece a MainActivity. Luego, se llama a estas de forma iterativa dentro de entryProvider,
lo que elimina la necesidad de llamar de forma explícita a numerosas funciones de compilador de entradas.
Módulo de funciones
// 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() } }
Módulo de app
// 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() } }, // ... ) } } }
Si tus entradas de navegación necesitan navegar (por ejemplo, contienen elementos de la IU que navegan a pantallas nuevas), inserta un objeto capaz de modificar el estado de navegación de la app en cada función de compilador.
Modulariza los comparadores de vínculos directos
Si tu app admite vínculos directos y está modularizada, cada módulo de funciones debería definir las instancias de DeepLinkMatcher para los destinos que posee.
Para recopilar todos los comparadores de tu app, puedes usar
las vinculaciones múltiples de inserción de dependencias. Por ejemplo, cada módulo de funciones puede aportar sus comparadores a una vinculación múltiple de @IntoSet de Dagger:
Módulo de funciones
@Module @InstallIn(ActivityRetainedComponent::class) object FeatureADeepLinkModule { @IntoSet @Provides fun provideUserMatcher(): DeepLinkMatcher<*, *> { return UriDeepLinkMatcher( DeepLinkUri("www.example.com/users/{id}"), serializer<UserProfileKey>() ) } }
Luego, en el módulo principal de la app, como en tu MainActivity, puedes insertar
el conjunto de comparadores y usarlos para que coincidan con las solicitudes entrantes:
Módulo de app
@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) } } }
Para obtener más información sobre cómo definir y controlar los vínculos directos, consulta Cómo admitir vínculos directos.
Recursos
Para ver muestras de código que ilustran cómo modularizar el código de Navigation 3, consulta los siguientes recursos:
- Recetas de código de la arquitectura de Navigation 3
- Recorrido de aprendizaje sobre modularización de la app de Now in Android
- Androidify