Ominaisuus- ja ydinmoduulit
Määritelkää moduulien rajat.
Ominaisuus- ja ydinmoduulit on ilmainen Android Academy-oppitunti CoddyKitissä. Tämä on oppitunti 2/4. Voit lukea tästä oppimispolusta kokonaan mitkä tahansa 3 oppituntia ilmaiseksi — sen jälkeen CoddyKit PRO avaa kaikki oppitunnit sekä käytännön harjoittelun sisäänrakennetulla koodieditorilla ja ympäri vuorokauden toimivalla tekoälytuutorilla. Oppitunti kuuluu Android Academy-oppimispolkuun, ja edistymisesi synkronoituu verkon ja CoddyKit-sovelluksen välillä. Android Academy-kurssilla on yhteensä 4 oppituntia.
Kahdenlaiset moduulit
Useimmat modularisoidut Android-sovellukset järjestävät koodin kahteen pääasialliseen moduulityyppiin: feature- ja core-moduuleihin sekä niiden päällä olevaan ohueen :app-moduuliin.
- Feature-moduulit sisältävät yhden käyttäjälle näkyvän osan sovelluksesta (näkymän tai toiminnon).
- Core-moduulit sisältävät useiden feature-moduulien käyttämän yhteisen infrastruktuurin.
Tässä oppitunnissa opitte piirtämään nämä rajat hyvin.
Feature-moduulin rakenne
Feature-moduuli, kuten :feature:profile, sisältää kaiken, mitä yksi ominaisuus tarvitsee: Compose-näkymät, oman ViewModel-mallin ja käyttöliittymän tilan. Se on vertikaalinen: se omistaa kokonaisen osan käyttöliittymästä näkymämalliin asti.
Se riippuu yhteisten osien osalta core-moduuleista, mutta sen ei pitäisi riippua muista feature-moduuleista.
// 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()
}
}Featuren ViewModel
Jokainen feature omistaa oman ViewModel-mallinsa. Se hakee datan core-moduulissa olevan repositoryn kautta ja tarjoaa käyttöliittymän tilan. Feature-moduulin ei tarvitse tietää, miten data haetaan, vaan ainoastaan repositoryn sopimus.
// 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)
}Core-moduulin rakenne
Core-moduuli on horisontaalinen: se tarjoaa yhden ominaisuuden, jota käytetään eri feature-moduuleissa. Yleisiä core-moduuleja ovat:
:core:model— kaikkialla jaetut tavalliset dataluokat:core:network— Retrofit/Ktor-asiakasohjelmat:core:database— Room-asetukset:core:data— verkon ja tietokannan yhdistävät repositoryt:core:designsystem— teema ja uudelleenkäytettävät composable-funktiot
// core/model/User.kt
data class User(
val id: String,
val name: String,
val avatarUrl: String
)Design system -moduuli
:core:designsystem on yksi eniten uudelleenkäytetyistä moduuleista. Se sisältää MaterialTheme-teeman, väriteemat, typografian ja uudelleenkäytettävät composable-funktiot, kuten painikkeet ja kortit. Jokainen feature käyttää samaa ulkoasua ilman koodin kopioimista.
// 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
)
}Data-moduuli omistaa repositoryt
:core:data-moduuli tarjoaa repository-rajapinnat, joista feature-moduulit riippuvat, ja piilottaa samalla toteutuksen. Se riippuu yleensä moduuleista :core:network ja :core:database sekä yhdistää ne yhdeksi totuuden lähteeksi.
// 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()) }
}Pidä model- ja designsystem-moduulit kevyinä
Alimman tason ydinmoduulien tulisi riippua mahdollisimman vähästä. :core:model-moduulilla ei ihannetapauksessa ole lainkaan Android-riippuvuuksia – vain tavallisia Kotlinin dataluokkia. Näin sitä voi käyttää kaikkialla, ja sen kääntäminen on nopeaa.
Jos :core:model alkaisi riippua Retrofitistä tai Roomista, jokainen dataluokkiasi käyttävä moduuli vetäisi mukanaan myös nämä raskaat kirjastot.
// core/model/build.gradle.kts
plugins {
id("myapp.jvm.library") // pure Kotlin, no Android
}
// No Retrofit, no Room, no Compose here — just data classesOhut :app-moduuli
:app-moduuli toimii kokoajana. Sen tulisi sisältää hyvin vähän logiikkaa: Application-luokka, ainoa MainActivity, ylimmän tason NavHost ja riippuvuuksien injektoinnin määritykset. Kaikki varsinaiset näkymät sijaitsevat ominaisuusmoduuleissa.
Ohut sovellusmoduuli tarkoittaa, että useimmat muutokset tehdään ominaisuuksissa, joten sovellusmoduulia tarvitsee kääntää uudelleen vain harvoin.
// 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
}
}
}
}Hyvien rajojen määrittäminen
Miten päätät, mistä tulee moduuli? Tässä on käytännöllisiä nyrkkisääntöjä:
- Ominaisuus = näkymä tai toiminto, jolle käyttäjä osaa antaa nimen (Home, Profile, Checkout).
- Core-moduuli = toiminnallisuus, jota vähintään kaksi ominaisuutta käyttää uudelleen.
- Jos kaksi ominaisuutta tarvitsee samaa koodia, siirrä se alemmas core-moduuliin.
- Jos moduuli tekee liian monia toisiinsa liittymättömiä asioita, jaa se osiin.
Valinnainen: api- ja impl-jako
Suurissa sovelluksissa ominaisuus jaetaan joskus julkiseen :feature:profile:api-moduuliin (rajapinnat ja navigointireitit) ja yksityiseen :feature:profile:impl-moduuliin (näkymät ja view modelit). Muut ominaisuudet riippuvat vain pienestä api-moduulista, eivät koskaan toteutuksesta.
Tämä on edistynyt ratkaisu; useimmille sovelluksille yksi moduuli ominaisuutta kohti riittää hyvin. On kuitenkin hyvä tietää, että tämä malli on olemassa erittäin suuria koodikantoja varten.
// 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)
}Riippuvuusgraafin kokoaminen
Näin kerrokset liittyvät toisiinsa esimerkissämme. Huomaa, että riippuvuudet osoittavat aina vain alaspäin: 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)Pikatarkistus
Sekä :feature:home- että :feature:profile-moduulisi tarvitsevat käyttäjätietojen hakemista ja välimuistiin tallentamista. Missä repositoriokoodin tulisi sijaita?
Kertaus: ominaisuus- ja core-moduulit
Opit jakamaan koodin kahteen kerrokseen:
- Ominaisuusmoduulit ovat pystysuuntaisia kokonaisuuksia (näkymä + ViewModel + käyttöliittymän tila).
- Core-moduulit ovat vaakasuuntaisia toiminnallisuuksia (model, network, database, data, designsystem).
:app-moduuli pysyy ohuena ja kokoaa vain ominaisuudet yhteen.- Jaettu koodi siirretään alemmas coreen;
:core:modelpysyy Androidista riippumattomana ja kevyenä.
Seuraavaksi hallitset näiden moduulien välisiä riippuvuuksia ja pidät graafin siistinä.
Opi Kotlin tekoälytuutorin avulla — ilmaiseksi
Kirjoita ja suorita oikeaa koodia selaimessa, saa välitöntä apua tekoälytuutorilta ympäri vuorokauden ja jatka siitä, mihin jäit, verkossa tai sovelluksessa.
- Kurssit
- 36
- Oppitunnit
- 152
Usein kysytyt kysymykset
Onko oppitunti ”Ominaisuus- ja ydinmoduulit” ilmainen?
Kyllä — voit lukea täällä verkossa kokonaan ilmaiseksi mitkä tahansa Android Academy-oppimispolun 3 oppituntia, myös oppitunnin “Ominaisuus- ja ydinmoduulit”. Sen jälkeen CoddyKit PRO avaa kaikki oppitunnit sekä interaktiiviset harjoitukset sisäänrakennetulla koodieditorilla ja ympäri vuorokauden toimivalla tekoälytuutorilla. Android Academy-kurssilla on yhteensä 4 oppituntia.
Mitä opin oppitunnilla ”Ominaisuus- ja ydinmoduulit”?
Määritelkää moduulien rajat. Harjoittelet Android Academy-aihetta koodilla, jonka suoritat suoraan selaimessa. Ympäri vuorokauden käytettävissä oleva tekoälytuutori vastaa kysymyksiisi oppitunnin aikana.
Tarvitsenko kokemusta aloittaakseni Android Academy-opiskelun?
Aiempi kokemus ei ole tarpeen. CoddyKitin Android Academy-oppimispolku sopii vasta-alkajista edistyneisiin, joten voit aloittaa tästä tai alusta ja edetä omaan tahtiisi. Tämä on oppitunti 2/4.
Kuinka kauan ”Ominaisuus- ja ydinmoduulit”-oppitunnin suorittaminen kestää?
Useimmat CoddyKitin oppitunnit kestävät noin 5–10 minuuttia. Jokainen oppitunti on lyhyt ja interaktiivinen, joten edistyt tasaisesti ja voit jatkaa siitä, mihin jäit – sekä verkossa että sovelluksessa.
Voinko kirjoittaa ja suorittaa koodia tällä Android Academy-oppitunnilla?
Kyllä. Jokainen Android Academy-oppitunti sisältää sisäänrakennetun koodieditorin, joten voit kirjoittaa ja suorittaa oikeaa koodia suoraan selaimessa ja saada välitöntä palautetta tekoälyltä – paikallista asennusta ei tarvita.
Kaikki tämän kurssin oppitunnit
- Miksi modularisoida
- Ominaisuus- ja ydinmoduulit
- Moduuliriippuvuuksien hallinta
- Navigointi moduulien välillä