Android Academy · Oppitunti

Ominaisuus- ja ydinmoduulit

Määritelkää moduulien rajat.

Oppitunti 2/413 vaihetta

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 classes

Ohut :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:model pysyy Androidista riippumattomana ja kevyenä.

Seuraavaksi hallitset näiden moduulien välisiä riippuvuuksia ja pidät graafin siistinä.

Aloita maksutta

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

  1. Miksi modularisoida
  2. Ominaisuus- ja ydinmoduulit
  3. Moduuliriippuvuuksien hallinta
  4. Navigointi moduulien välillä
← Takaisin: Android Academy