Moduły funkcji i moduły podstawowe
Wyznacz granice modułów
Moduły funkcji i moduły podstawowe to bezpłatna lekcja Android Academy na CoddyKit. To lekcja 2 z 4. Możesz przeczytać całą lekcję poniżej za darmo — a potem ćwiczyć ją interaktywnie w przeglądarce z wbudowanym edytorem kodu i tutorem AI dostępnym 24/7. To część ścieżki edukacyjnej Android Academy, a Twój postęp synchronizuje się między webem a aplikacją CoddyKit. Kurs Android Academy zawiera 4 lekcji w sumie.
Dwa rodzaje modułów
W większości zmodularyzowanych aplikacji na Androida kod jest uporządkowany w dwóch głównych rodzajach modułów: modułach feature i core, a nad nimi znajduje się niewielki moduł :app.
- Moduły feature zawierają fragment aplikacji widoczny dla użytkownika (ekran lub przepływ).
- Moduły core zawierają współdzieloną infrastrukturę używaną przez wiele funkcji.
W tej lekcji dowie się Pan lub dowie się Pani, jak prawidłowo wyznaczać te granice.
Budowa modułu funkcji
Moduł funkcji, taki jak :feature:profile, zawiera wszystko, czego potrzebuje jedna funkcja: ekrany Compose, obiekt ViewModel oraz stan interfejsu użytkownika. Jest pionowy: obejmuje cały fragment od interfejsu użytkownika po model widoku.
Zależy od modułów core w zakresie współdzielonych elementów, ale nie powinien zależeć od innych modułów funkcji.
// 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()
}
}ViewModel funkcji
Każda funkcja ma własny obiekt ViewModel. Pobiera on dane za pośrednictwem repozytorium z modułu core i udostępnia stan interfejsu użytkownika. Moduł funkcji nie wie, w jaki sposób pobierane są dane — zna jedynie kontrakt repozytorium.
// 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)
}Budowa modułu core
Moduł core jest poziomy: udostępnia jedną funkcję używaną w wielu modułach. Typowe moduły core to:
:core:model— zwykłe klasy danych współdzielone w całej aplikacji:core:network— klienty Retrofit/Ktor:core:database— konfiguracja Room:core:data— repozytoria łączące sieć i bazę danych:core:designsystem— motyw i kompozysy wielokrotnego użytku
// core/model/User.kt
data class User(
val id: String,
val name: String,
val avatarUrl: String
)Moduł systemu projektowego
:core:designsystem jest jednym z najczęściej wykorzystywanych modułów. Zawiera MaterialTheme, schematy kolorów, typografię oraz kompozysy wielokrotnego użytku, takie jak przyciski i karty. Każda funkcja korzysta z takiego samego wyglądu bez kopiowania kodu.
// 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
)
}Moduł danych odpowiada za repozytoria
Moduł :core:data udostępnia interfejsy repozytoriów, od których zależą moduły funkcji, ukrywając jednocześnie implementację. Zwykle zależy od modułów :core:network i :core:database, łącząc je w jedno źródło prawdy.
// 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()) }
}Lekki model i design system
Moduły rdzeniowe najniższego poziomu powinny zależeć od możliwie najmniejszej liczby elementów. :core:model najlepiej, aby w ogóle nie miał zależności od Androida — tylko zwykłe klasy danych Kotlin. Dzięki temu można go używać wszędzie, a jego kompilacja jest szybka.
Gdyby :core:model zaczął zależeć od Retrofit lub Room, każdy moduł korzystający z klas danych musiałby dołączyć te ciężkie biblioteki.
// core/model/build.gradle.kts
plugins {
id("myapp.jvm.library") // pure Kotlin, no Android
}
// No Retrofit, no Room, no Compose here — just data classesCienki moduł :app
Moduł :app pełni rolę składacza. Powinien zawierać bardzo niewiele logiki: klasę Application, pojedynczą klasę MainActivity, główny NavHost oraz konfigurację wstrzykiwania zależności. Wszystkie rzeczywiste ekrany znajdują się w modułach funkcjonalności.
Cienki moduł aplikacji oznacza, że większość zmian zachodzi w modułach funkcjonalności, więc moduł aplikacji rzadko wymaga ponownej kompilacji.
// 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
}
}
}
}Wyznaczanie dobrych granic
Jak zdecydować, co powinno stać się modułem? Oto kilka praktycznych wskazówek:
- Funkcjonalność = ekran lub przepływ, który użytkownik może nazwać (Home, Profile, Checkout).
- Moduł core = możliwość wykorzystywana przez co najmniej 2 funkcjonalności.
- Jeśli dwie funkcjonalności potrzebują tego samego kodu, przenieś go niżej, do modułu core.
- Jeśli moduł robi zbyt wiele niezwiązanych ze sobą rzeczy, podziel go.
Opcjonalnie: podział na api i impl
Duże aplikacje czasami dzielą funkcjonalność na publiczny moduł :feature:profile:api (interfejsy, trasy nawigacji) oraz prywatny moduł :feature:profile:impl (ekrany, modele widoku). Inne funkcjonalności zależą tylko od niewielkiego modułu api, nigdy od implementacji.
To rozwiązanie zaawansowane; w większości aplikacji pojedynczy moduł na funkcjonalność w zupełności wystarczy. Warto jednak wiedzieć, że w bardzo dużych bazach kodu stosuje się taki wzorzec.
// 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)
}Łączenie grafu
Tak warstwy łączą się w naszym przykładzie. Zwróć uwagę, że zależności zawsze wskazują w dół: 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)Szybkie sprawdzenie
Moduły :feature:home i :feature:profile muszą pobierać i buforować dane użytkownika. Gdzie powinien znajdować się kod repozytorium?
Podsumowanie: moduły funkcjonalności i core
Nauczyłeś się dzielić kod na dwie warstwy:
- Moduły funkcjonalności to pionowe wycinki (ekran + ViewModel + stan interfejsu użytkownika).
- Moduły core to poziome możliwości (model, sieć, baza danych, dane, design system).
- Moduł
:apppozostaje cienki i tylko składa funkcjonalności. - Wspólny kod przenosi się niżej, do core;
:core:modelpozostaje niezależny od Androida i lekki.
W następnej części zajmiesz się zależnościami między tymi modułami i utrzymaniem przejrzystego grafu.
Często zadawane pytania
Czy lekcja „Moduły funkcji i moduły podstawowe” jest bezpłatna?
Tak — pełny tekst „Moduły funkcji i moduły podstawowe” jest dostępny za darmo tutaj w sieci. Aby ćwiczyć ją interaktywnie (wbudowany edytor kodu i tutor AI dostępny 24/7) i odblokować resztę kursu Android Academy, przejdź na CoddyKit PRO. Kurs Android Academy zawiera 4 lekcji w sumie.
Co nauczysz się w „Moduły funkcji i moduły podstawowe”?
Wyznacz granice modułów Ćwiczysz Android Academy z praktycznym kodem, który uruchamiasz bezpośrednio w przeglądarce, a tutor AI dostępny 24/7 odpowiada na Twoje pytania podczas pracy nad lekcją.
Czy potrzebuję doświadczenia, aby zacząć Android Academy?
Nie wymagamy żadnego doświadczenia. Android Academy w CoddyKit jest strukturyzowany dla początkujących i zaawansowanych użytkowników, więc możesz zacząć tutaj lub od początku i uczyć się w swoim tempie. To lekcja 2 z 4.
Ile czasu zajmuje lekcja „Moduły funkcji i moduły podstawowe”?
Większość lekcji CoddyKit trwa około 5–10 minut. Każda lekcja to mały, interaktywny krok, dzięki czemu robisz systematyczne postępy i zawsze wracasz dokładnie do tego samego miejsca — na webie i w aplikacji.
Czy mogę pisać i uruchamiać kod w tej lekcji Android Academy?
Tak. Każda lekcja Android Academy zawiera wbudowany edytor kodu, więc piszesz i uruchamiasz prawdziwy kod bezpośrednio w przeglądarce i od razu otrzymujesz sprzężenie zwrotne od AI — bez konfiguracji na komputerze.
Wszystkie lekcje w tym kursie
- Dlaczego warto stosować moduły
- Moduły funkcji i moduły podstawowe
- Zarządzanie zależnościami modułów
- Nawigacja między modułami