Android Academy · Lektion

Feature- og core-moduler

Træk modulgrænserne.

Lektion 2 af 413 trin

Feature- og core-moduler er en gratis Android Academy-lektion på CoddyKit. Dette er lektion 2 af 4. Du kan læse alle 3 lektioner i dette læringsspor gratis i deres fulde længde — derefter låser CoddyKit PRO alle lektioner op samt praktiske øvelser med en indbygget kodeeditor og en AI-underviser døgnet rundt. Den er en del af læringsforløbet i Android Academy, og dine fremskridt synkroniseres på tværs af nettet og CoddyKit-appen. Android Academy-kurset indeholder 4 lektioner i alt.

To slags moduler

De fleste modulariserede Android-apps organiserer koden i to hovedtyper af moduler: feature-moduler og core-moduler samt et tyndt :app-modul øverst.

  • Feature-moduler indeholder en del af appen, der vender mod brugeren (en skærm eller et flow).
  • Core-moduler indeholder fælles infrastruktur, der bruges af mange funktioner.

I denne lektion lærer du, hvordan du trækker disse grænser på en god måde.

Et feature-moduls anatomi

Et feature-modul som :feature:profile indeholder alt, hvad én funktion har brug for: dens Compose-skærme, dens ViewModel og dens UI-tilstand. Det er vertikalt: Det ejer hele udsnittet fra brugergrænsefladen ned til sin view-model.

Det afhænger af core-moduler for fælles dele, men det bør ikke afhænge af andre feature-moduler.

// feature/profile/ProfileScreen.kt
@Composable
fun ProfileScreen(viewModel: ProfileViewModel = hiltViewModel()) {
    val state by viewModel.uiState.collectAsStateWithLifecycle()
    when (state) {
        is ProfileUiState.Loading -> CircularProgressIndicator()
        is ProfileUiState.Success -> ProfileContent((state as ProfileUiState.Success).user)
        is ProfileUiState.Error -> ErrorMessage()
    }
}

Feature-modulets ViewModel

Hver funktion ejer sin egen ViewModel. Den henter data gennem et repository fra et core-modul og eksponerer UI-tilstand. Feature-modulet ved ikke noget om, hvordan data hentes, men kun om repositoryets kontrakt.

// feature/profile/ProfileViewModel.kt
@HiltViewModel
class ProfileViewModel @Inject constructor(
    private val userRepository: UserRepository // from :core:data
) : ViewModel() {
    val uiState: StateFlow<ProfileUiState> =
        userRepository.observeUser()
            .map { ProfileUiState.Success(it) }
            .stateIn(viewModelScope, SharingStarted.WhileSubscribed(5000), ProfileUiState.Loading)
}

Et core-moduls anatomi

Et core-modul er horisontalt: Det leverer én funktionalitet, der bruges på tværs af funktioner. Almindelige core-moduler omfatter:

  • :core:model — almindelige dataklasser, der deles overalt
  • :core:network — Retrofit-/Ktor-klienter
  • :core:database — Room-opsætning
  • :core:data — repositories, der kombinerer netværk og database
  • :core:designsystem — tema og genbrugelige composables
// core/model/User.kt
data class User(
    val id: String,
    val name: String,
    val avatarUrl: String
)

Designsystemmodulet

:core:designsystem er et af de mest genbrugte moduler. Det indeholder din MaterialTheme, farveskemaer, typografi og genbrugelige composables som knapper og kort. Alle funktioner anvender det samme udseende uden at kopiere kode.

// core/designsystem/AppTheme.kt
@Composable
fun AppTheme(
    darkTheme: Boolean = isSystemInDarkTheme(),
    content: @Composable () -> Unit
) {
    val colors = if (darkTheme) DarkColors else LightColors
    MaterialTheme(
        colorScheme = colors,
        typography = AppTypography,
        content = content
    )
}

Datamodulet ejer repositories

:core:data-modulet eksponerer repository-grænseflader, som funktioner afhænger af, mens det skjuler implementeringen. Det afhænger normalt af :core:network og :core:database og kombinerer dem til en enkelt sandhedskilde.

// core/data/UserRepository.kt
interface UserRepository {
    fun observeUser(): Flow<User>
    suspend fun refresh()
}

// core/data/OfflineFirstUserRepository.kt
internal class OfflineFirstUserRepository @Inject constructor(
    private val api: UserApi,        // :core:network
    private val dao: UserDao         // :core:database
) : UserRepository {
    override fun observeUser(): Flow<User> = dao.observe().map { it.toUser() }
    override suspend fun refresh() { dao.upsert(api.fetch().toEntity()) }
}

Hold model- og designsystemet lette

Modulerne i kernen på det laveste niveau bør afhænge af så lidt som muligt. :core:model bør helst slet ikke have Android-afhængigheder — kun almindelige Kotlin-dataklasser. Det gør modulet anvendeligt overalt og hurtigt at bygge.

Hvis :core:model begyndte at afhænge af Retrofit eller Room, ville hvert modul, der bruger dine dataklasser, trække disse tunge biblioteker med ind.

// core/model/build.gradle.kts
plugins {
    id("myapp.jvm.library") // pure Kotlin, no Android
}
// No Retrofit, no Room, no Compose here — just data classes

Det tynde :app-modul

:app-modulet er samleren. Det bør indeholde meget lidt logik: Application-klassen, den ene MainActivity, den overordnede NavHost og opsætningen af afhængighedsinjektion. Alle egentlige skærme hører hjemme i funktionsmoduler.

Et tyndt app-modul betyder, at de fleste ændringer sker i funktionerne, så app-modulet sjældent skal bygges igen.

// app/MainActivity.kt
@AndroidEntryPoint
class MainActivity : ComponentActivity() {
    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContent {
            AppTheme {            // from :core:designsystem
                AppNavHost()      // routes into :feature:* screens
            }
        }
    }
}

Sådan laver du gode grænser

Hvordan beslutter du, hvad der skal blive et modul? Her er nogle praktiske tommelfingerregler:

  • En funktion = en skærm eller et forløb, som en bruger kan sætte navn på (Startside, Profil, Betaling).
  • Et kernemodul = en egenskab, der genbruges af mindst 2 funktioner.
  • Hvis to funktioner har brug for den samme kode, skal du flytte den ned i et kernemodul.
  • Hvis et modul gør for mange uvedkommende ting, skal du opdele det.

Valgfrit: Opdeling i api og impl

Store apps opdeler nogle gange en funktion i et offentligt :feature:profile:api (grænseflader og navigationsruter) og et privat :feature:profile:impl (skærme og view-modeller). Andre funktioner afhænger kun af det lille api og aldrig af implementeringen.

Dette er avanceret. For de fleste apps er ét modul pr. funktion rigeligt. Du skal blot vide, at mønsteret findes til meget store kodebaser.

// Other features see only the contract, not the screens
// feature/home depends on :feature:profile:api
interface ProfileEntry {
    val route: String
    fun NavGraphBuilder.register(navController: NavController)
}

Saml grafen

Sådan forbindes lagene i vores eksempel. Bemærk, at afhængigheder altid kun peger nedad: app -> feature -> data -> network/database -> model.

// :app           -> :feature:home, :feature:profile
// :feature:home  -> :core:data, :core:designsystem
// :feature:profile -> :core:data, :core:designsystem
// :core:data     -> :core:network, :core:database, :core:model
// :core:network  -> :core:model
// :core:database -> :core:model
// :core:model    -> (nothing)

Hurtigt tjek

Dine :feature:home- og :feature:profile-moduler skal begge hente og cache brugerdata. Hvor bør repository-koden ligge?

Opsummering: Funktions- og kernemoduler

Du har lært at opdele kode i to lag:

  • Funktionsmoduler er lodrette udsnit (skærm + ViewModel + brugerfladetilstand).
  • Kernemoduler er vandrette egenskaber (model, netværk, database, data, designsystem).
  • :app-modulet forbliver tyndt og samler blot funktionerne.
  • Fælles kode flyttes ned i kernen; :core:model forbliver frit for Android-afhængigheder og let.

Nu skal du håndtere afhængighederne mellem disse moduler og holde grafen ren.

Gratis at komme i gang

Lær Kotlin med en AI-underviser — gratis

Skriv og kør rigtig kode i din browser, få øjeblikkelig hjælp fra en AI-underviser døgnet rundt, og fortsæt, hvor du slap, på web eller i appen.

Kurser
36
Lektioner
152

Ofte stillede spørgsmål

Er lektionen “Feature- og core-moduler” gratis?

Ja — alle 3 lektioner i læringssporet Android Academy, inklusive “Feature- og core-moduler”, kan læses gratis i deres fulde længde her på webstedet. Derefter låser CoddyKit PRO alle lektioner op samt interaktive øvelser med en indbygget kodeeditor og en AI-underviser døgnet rundt. Android Academy-kurset indeholder 4 lektioner i alt.

Hvad lærer jeg i “Feature- og core-moduler”?

Træk modulgrænserne. Du øver dig i Android Academy med praktisk kode, som du kører direkte i browseren, og en AI-vejleder døgnet rundt besvarer dine spørgsmål, mens du arbejder dig gennem lektionen.

Skal jeg have erfaring for at begynde på Android Academy?

Der kræves ingen tidligere erfaring. Android Academy på CoddyKit er tilrettelagt for både begyndere og øvede, så du kan starte her eller fra begyndelsen og lære i dit eget tempo. Dette er lektion 2 af 4.

Hvor lang tid tager lektionen “Feature- og core-moduler”?

De fleste CoddyKit-lektioner tager cirka 5–10 minutter. Hver lektion er kort og interaktiv, så du gør løbende fremskridt og kan fortsætte, hvor du slap – på både web og app.

Kan jeg skrive og køre kode i denne Android Academy-lektion?

Ja. Alle Android Academy-lektioner har en indbygget kodeeditor, så du kan skrive og køre rigtig kode direkte i din browser og få øjeblikkelig feedback fra AI – uden lokal opsætning.

Alle lektioner i dette kursus

  1. Hvorfor modularisere
  2. Feature- og core-moduler
  3. Håndtering af modulafhængigheder
  4. Navigation på tværs af moduler
← Tilbage til Android Academy