בדף הזה מוצגות כמה שיטות מומלצות והמלצות בנושא ארכיטקטורה. כדאי להשתמש בהם כדי לשפר את האיכות, היציבות והגמישות של האפליקציה. הם גם מקלים על התחזוקה והבדיקה של האפליקציה.
השיטות המומלצות שבהמשך מחולקות לפי נושאים. לכל המלצה יש עדיפות שמשקפת את מידת החשיבות שלה. רשימת העדיפויות היא:
- מומלץ מאוד: כדאי ליישם את השיטה הזו, אלא אם היא סותרת באופן מהותי את הגישה שלכם.
- מומלץ: סביר להניח שהשיטה הזו תשפר את האפליקציה.
- אופציונלי: במקרים מסוימים, שימוש בשיטה הזו יכול לשפר את האפליקציה.
ארכיטקטורה שכבתית
הארכיטקטורה השכבתית המומלצת שלנו מעודדת הפרדה בין תחומים. הוא מפעיל את ממשק המשתמש ממודלים של נתונים, עומד בדרישות של העיקרון 'מקור מרוכז אחד' ופועל לפי העקרונות של זרימת נתונים חד-כיוונית. ריכזנו כאן כמה שיטות מומלצות לארכיטקטורה שכבתית:
| המלצה | תיאור |
|---|---|
| להשתמש בשכבת נתונים מוגדרת בבירור.
מומלץ מאוד |
שכבת הנתונים חושפת את נתוני האפליקציה לשאר האפליקציה ומכילה את רוב הלוגיקה העסקית של האפליקציה.
|
| משתמשים בשכבת ממשק משתמש מוגדרת בבירור.
מומלץ מאוד |
שכבת ממשק המשתמש מציגה את נתוני האפליקציה במסך ומשמשת כנקודת אינטראקציית המשתמש העיקרית. Jetpack פיתוח נייטיב היא ערכת הכלים המודרנית המומלצת לבניית ממשק המשתמש של האפליקציה.
|
| חשיפת נתוני אפליקציה משכבת הנתונים באמצעות מאגר.
מומלץ מאוד |
מוודאים שרכיבים בשכבת ממשק המשתמש, כמו פונקציות Composable או ViewModels, לא מקיימים אינטראקציה ישירה עם מקור נתונים. דוגמאות למקורות נתונים:
|
| משתמשים בקורוטינות וב-Flows.
מומלץ מאוד |
משתמשים בקורוטינות וב-Flows כדי לתקשר בין השכבות.
מידע נוסף על שיטות מומלצות לשימוש בקורוטינות זמין במאמר בנושא שיטות מומלצות לשימוש בקורוטינות ב-Android. |
| משתמשים בשכבת דומיין.
מומלץ באפליקציות גדולות |
משתמשים בשכבת דומיין עם תרחישי שימוש אם רוצים לעשות שימוש חוזר בלוגיקה עסקית שמתקשרת עם שכבת הנתונים בכמה ViewModels, או אם רוצים לפשט את המורכבות של הלוגיקה העסקית של ViewModel מסוים |
שכבת ממשק המשתמש
התפקיד של שכבת ממשק המשתמש הוא להציג את נתוני האפליקציה במסך ולשמש כנקודת האינטראקציה העיקרית של המשתמש. ריכזנו כאן כמה שיטות מומלצות לשכבת ממשק המשתמש:
| המלצה | תיאור |
|---|---|
| פועלים לפי ההנחיות בנושא זרימת נתונים חד-כיוונית (UDF).
מומלץ מאוד |
פועלים לפי העקרונות של זרימת נתונים חד-כיוונית (UDF), שבהם ViewModels חושפים את מצב ממשק המשתמש באמצעות תבנית הצופה ומקבלים פעולות מממשק המשתמש באמצעות קריאות לשיטות. |
| כדאי להשתמש ב-AAC ViewModels אם היתרונות שלהם רלוונטיים לאפליקציה שלכם.
מומלץ מאוד |
משתמשים ב-AAC ViewModels כדי לטפל בלוגיקה העסקית, ומאחזרים נתוני אפליקציה כדי לחשוף את מצב ממשק המשתמש לממשק המשתמש.
מידע נוסף על שיטות מומלצות לשימוש ב-ViewModel זמין במאמר המלצות לארכיטקטורה. מידע נוסף על היתרונות של ViewModels זמין במאמר The ViewModel as a business logic state holder. |
| שימוש באיסוף מצב ממשק משתמש שמודע למחזור החיים.
מומלץ מאוד |
אוספים את מצב ממשק המשתמש מהממשק באמצעות כלי ליצירת קורוטינות שמתאים למחזור החיים, collectAsStateWithLifecycle.
מידע נוסף על |
| אל תשלחו אירועים מ-ViewModel לממשק המשתמש.
מומלץ מאוד |
מעבדים את האירוע באופן מיידי ב-ViewModel וגורמים לעדכון המצב עם התוצאה של הטיפול באירוע. מידע נוסף על אירועי ממשק משתמש זמין במאמר טיפול באירועים של ViewModel. |
| שימוש באפליקציה עם פעילות אחת.
מומלץ מאוד |
אם לאפליקציה יש יותר ממסך אחד, משתמשים בNavigation 3 כדי לנווט בין המסכים ולקשר עמוק לאפליקציה. |
| משתמשים ב-Jetpack פיתוח נייטיב.
מומלץ מאוד |
אפשר להשתמש ב-Jetpack פיתוח נייטיב כדי לבנות אפליקציות חדשות לטלפונים, לטאבלטים, למכשירים מתקפלים ול-Wear OS. |
בקטע הקוד הבא אפשר לראות איך אוספים את מצב ממשק המשתמש באופן שמודע למחזור החיים:
@Composable
fun MyScreen(
viewModel: MyViewModel = viewModel()
) {
val uiState by viewModel.uiState.collectAsStateWithLifecycle()
}
ViewModel
ViewModels אחראים לספק את מצב ממשק המשתמש ולגשת לשכבת הנתונים. ריכזנו כאן כמה שיטות מומלצות לשימוש ב-ViewModels:
| המלצה | תיאור |
|---|---|
| חשוב לשמור על עצמאות של ViewModels ממחזור החיים של Android.
מומלץ מאוד |
ב-ViewModels, אל תחזיקו הפניה לסוג שקשור למחזור חיים. אל תעבירו את Activity, Context או Resources כתלות.
אם משהו צריך Context ב-ViewModel, צריך לבדוק בקפידה אם הוא נמצא בשכבה הנכונה. |
| משתמשים בקורוטינות וב-Flows.
מומלץ מאוד |
ה-ViewModel מתקשר עם שכבות הנתונים או הדומיין באמצעות:
|
| משתמשים ב-ViewModels ברמת המסך.
מומלץ מאוד |
אל תשתמשו ב-ViewModels בחלקים של ממשק משתמש שאפשר לעשות בהם שימוש חוזר. כדאי להשתמש ב-ViewModels במקרים הבאים:
|
| משתמשים במחזיקי מצב פשוטים ברכיבי ממשק משתמש שאפשר לעשות בהם שימוש חוזר.
מומלץ מאוד |
כדי לטפל במורכבות ברכיבי ממשק משתמש לשימוש חוזר, משתמשים במחזיקי מצב פשוטים. כשעושים את זה, אפשר להעלות את המצב ולשלוט בו מבחוץ. |
אל תשתמשו ב-AndroidViewModel.
מומלץ |
משתמשים במחלקת ViewModel ולא במחלקת AndroidViewModel. אל תשתמשו במחלקה Application ב-ViewModel. במקום זאת, מעבירים את התלות לממשק המשתמש או לשכבת הנתונים. |
| חשיפת מצב של ממשק משתמש.
מומלץ |
הגדרת ViewModels כך שיחשפו נתונים לממשק המשתמש באמצעות מאפיין יחיד שנקרא uiState. אם בממשק המשתמש מוצגים כמה נתונים לא קשורים, המכונה הווירטואלית יכולה לחשוף כמה מאפיינים של מצב ממשק המשתמש.
|
בקטע הקוד הבא אפשר לראות איך חושפים את מצב ממשק המשתמש מ-ViewModel:
@HiltViewModel
class BookmarksViewModel @Inject constructor(
newsRepository: NewsRepository
) : ViewModel() {
val feedState: StateFlow<NewsFeedUiState> =
newsRepository
.getNewsResourcesStream()
.mapToFeedState(savedNewsResourcesState)
.stateIn(
scope = viewModelScope,
started = SharingStarted.WhileSubscribed(5_000),
initialValue = NewsFeedUiState.Loading
)
// ...
}
מחזור חיים
פועלים לפי השיטות המומלצות לעבודה עם מחזור החיים של פעילות:
| המלצה | תיאור |
|---|---|
מומלץ להשתמש באפקטים שמתעדכנים בהתאם למחזור החיים ברכיבים קומפוזביליים במקום לבטל את ההגדרות של מחזורי החיים של Activity.
מומלץ מאוד |
אל תבטלו את השיטות של מחזור החיים
|
בקטע הקוד הבא מוסבר איך לבצע פעולות בהינתן מצב מחזור חיים מסוים:
@Composable
fun LocationChangedEffect(
locationManager: LocationManager,
onLocationChanged: (Location) -> Unit
) {
val currentOnLocationChanged by rememberUpdatedState(onLocationChanged)
LifecycleStartEffect(locationManager) {
val listener = LocationListener { newLocation ->
currentOnLocationChanged(newLocation)
}
try {
locationManager.requestLocationUpdates(
LocationManager.GPS_PROVIDER,
1000L,
1f,
listener,
)
} catch (e: SecurityException) {
// TODO: Handle missing permissions
}
onStopOrDispose {
locationManager.removeUpdates(listener)
}
}
}
טיפול ביחסי תלות
כדאי לפעול לפי השיטות המומלצות לניהול תלויות בין רכיבים:
| המלצה | תיאור |
|---|---|
| להשתמש בהזרקת תלות.
מומלץ מאוד |
מומלץ להשתמש בשיטות מומלצות של הזרקת תלות, בעיקר הזרקת בנאי כשזה אפשרי. |
| היקף לכל רכיב לפי הצורך.
מומלץ מאוד |
הגדרת היקף למאגר תלות כשסוג הנתונים מכיל נתונים שניתנים לשינוי וצריך לשתף אותם, או כשסוג הנתונים יקר לאתחול ונעשה בו שימוש נרחב באפליקציה. |
| שימוש ב-Hilt.
מומלץ |
באפליקציות פשוטות, אפשר להשתמש ב-Hilt או בהחדרת תלות ידנית. כדאי להשתמש ב-Hilt אם הפרויקט שלכם מורכב מספיק – לדוגמה, אם הוא כולל את אחד מהרכיבים הבאים:
|
בדיקה
ריכזנו כאן כמה שיטות מומלצות לבדיקות:
| המלצה | תיאור |
|---|---|
| מה כדאי לבדוק
מומלץ מאוד |
אלא אם הפרויקט פשוט כמו אפליקציית 'שלום עולם', כדאי לבדוק אותו. לפחות את הפרטים הבאים:
|
| עדיף להשתמש ב-fakes במקום ב-mocks.
מומלץ מאוד |
מידע נוסף על השימוש ב-fakes מופיע במאמר שימוש ב-test doubles ב-Android. |
| בדיקת StateFlows.
מומלץ מאוד |
כשבודקים את StateFlow, מבצעים את הפעולות הבאות:
|
מידע נוסף זמין במאמרים מה כדאי לבדוק ב-Android ובדיקת פריסת פיתוח נייטיב.
מודלים
כדאי לפעול לפי השיטות המומלצות הבאות כשמפתחים מודלים באפליקציות:
| המלצה | תיאור |
|---|---|
| באפליקציות מורכבות, כדאי ליצור מודל לכל שכבה.
מומלץ |
באפליקציות מורכבות, כדאי ליצור מודלים חדשים בשכבות או ברכיבים שונים כשזה הגיוני. הנה כמה דוגמאות:
|
מוסכמות למתן שמות
כשנותנים שם לבסיס הקוד, כדאי לפעול לפי השיטות המומלצות הבאות:
| המלצה | תיאור |
|---|---|
| שיטות מתן שמות.
אופציונלי |
משתמשים בצירופי פועל כדי לתת שמות לשיטות – לדוגמה, makePayment(). |
| מתן שמות למאפיינים.
אופציונלי |
משתמשים בצירופי שם עצם כדי לתת שמות למאפיינים – לדוגמה, inProgressTopicSelection. |
| מתן שמות למקורות נתונים.
אופציונלי |
כשסיווג חושף זרם Flow או כל זרם אחר, מוסכמת מתן השמות היא get{model}Stream. לדוגמה, getAuthorStream(): Flow<Author>.
אם הפונקציה מחזירה רשימה של מודלים, צריך להשתמש בשם המודל ברבים: getAuthorsStream(): Flow<List<Author>>. |
| מתן שמות להטמעות של ממשקים.
אופציונלי |
חשוב להשתמש בשמות משמעותיים להטמעות של ממשקים. אם לא מוצאים שם טוב יותר, משתמשים ב-Default כקידומת. לדוגמה, בממשק NewsRepository יכול להיות שיהיה לכם OfflineFirstNewsRepository או InMemoryNewsRepository. אם לא מוצאים שם טוב, אפשר להשתמש ב-DefaultNewsRepository.
צריך להוסיף את הקידומת Fake להטמעות מזויפות, כמו בדוגמה FakeAuthorsRepository. |
מקורות מידע נוספים
למידע נוסף על ארכיטקטורת Android, אפשר להיעזר במקורות המידע הנוספים הבאים: