יצירת ViewModels עם יחסי תלות (Views) בארגז הכלים Android Jetpack.
מושגים ויישום ב-Jetpack פיתוח נייטיב
בהתאם לשיטות המומלצות של הזרקת תלות, אפשר להעביר את התלות כפרמטרים בבנאי של ViewModels. רובם הם מסוגים של שכבות הדומיין או הנתונים. מכיוון שה-ViewModels מסופקים על ידי המסגרת, נדרש מנגנון מיוחד כדי ליצור מופעים שלהם. המנגנון הזה הוא ממשק ViewModelProvider.Factory. רק הטמעות של הממשק הזה יכולות ליצור מופעים של ViewModels בהיקף הנכון.
ViewModels עם CreationExtras
אם מחלקה ViewModel מקבלת תלויות ב-constructor שלה, צריך לספק פקטורי (factory) שמטמיע את הממשק ViewModelProvider.Factory.
מבטלים את ההגדרה של הפונקציה create(Class<T>, CreationExtras) כדי לספק מופע חדש של ViewModel.
CreationExtras עם APPLICATION_KEY
בדוגמה הבאה אפשר לראות איך מספקים מופע של ViewModel שמקבל מאגר בהיקף של המחלקה Application ו-SavedStateHandle כתלות:
import static androidx.lifecycle.SavedStateHandleSupport.createSavedStateHandle;
import static androidx.lifecycle.ViewModelProvider.AndroidViewModelFactory.APPLICATION_KEY;
import androidx.lifecycle.SavedStateHandle;
import androidx.lifecycle.ViewModel;
import androidx.lifecycle.viewmodel.ViewModelInitializer;
public class MyViewModel extends ViewModel {
public MyViewModel(
MyRepository myRepository,
SavedStateHandle savedStateHandle
) { /* Init ViewModel here */ }
static final ViewModelInitializer<MyViewModel> initializer = new ViewModelInitializer<>(
MyViewModel.class,
creationExtras -> {
MyApplication app = (MyApplication) creationExtras.get(APPLICATION_KEY);
assert app != null;
SavedStateHandle savedStateHandle = createSavedStateHandle(creationExtras);
return new MyViewModel(app.getMyRepository(), savedStateHandle);
}
);
}
אחר כך אפשר להשתמש בפקטורי (factory) הזה כשמאחזרים מופע של ViewModel:
Kotlin
import androidx.activity.viewModels
class MyActivity : AppCompatActivity() {
private val viewModel: MyViewModel by viewModels { MyViewModel.Factory }
// Rest of Activity code
}
Java
import androidx.appcompat.app.AppCompatActivity;
import androidx.lifecycle.ViewModelProvider;
public class MyActivity extends AppCompatActivity {
MyViewModel myViewModel = new ViewModelProvider(
this,
ViewModelProvider.Factory.from(MyViewModel.initializer)
).get(MyViewModel.class);
// Rest of Activity code
}
העברה של פרמטרים מותאמים אישית כ-CreationExtras
אפשר להעביר תלויות אל ViewModel דרך CreationExtras על ידי יצירת מפתח מותאם אישית.
האפשרות הזו שימושית אם ViewModel תלוי באובייקטים שלא נגישים דרך המחלקה Application ו-APPLICATION_KEY. דוגמה למצב כזה היא כש-ViewModel נוצר בתוך מודול Kotlin Multiplatform ולכן אין לו גישה לתלות ב-Android.
בדוגמה הזו, ViewModel מגדיר מפתח מותאם אישית ומשתמש בו ב-ViewModelProvider.Factory.
import androidx.lifecycle.ViewModel
import androidx.lifecycle.ViewModelProvider
import androidx.lifecycle.viewModelScope
import androidx.lifecycle.viewmodel.CreationExtras
import androidx.lifecycle.viewmodel.initializer
import androidx.lifecycle.viewmodel.viewModelFactory
class MyViewModel(
private val myRepository: MyRepository,
) : ViewModel() {
// ViewModel logic
// Define ViewModel factory in a companion object
companion object {
// Define a custom key for your dependency
val MY_REPOSITORY_KEY = object : CreationExtras.Key<MyRepository> {}
val Factory: ViewModelProvider.Factory = viewModelFactory {
initializer {
// Get the dependency in your factory
val myRepository = this[MY_REPOSITORY_KEY] as MyRepository
MyViewModel(
myRepository = myRepository,
)
}
}
}
}
אפשר ליצור מופע של ViewModel עם CreationExtras.Key מתוך ViewModelStoreOwner כמו ComponentActivity, Fragment או NavBackStackEntry.
import androidx.lifecycle.ViewModelProvider
import androidx.lifecycle.ViewModelStoreOwner
import androidx.lifecycle.viewmodel.CreationExtras
import androidx.lifecycle.viewmodel.MutableCreationExtras
// ...
// Use from ComponentActivity, Fragment, NavBackStackEntry,
// or another ViewModelStoreOwner.
val viewModelStoreOwner: ViewModelStoreOwner = this
val myViewModel: MyViewModel = ViewModelProvider.create(
viewModelStoreOwner,
factory = MyViewModel.Factory,
extras = MutableCreationExtras().apply {
set(MyViewModel.MY_REPOSITORY_KEY, myRepository)
},
)[MyViewModel::class]
Factories לגרסת ViewModel ישנה יותר מ-2.5.0
אם אתם משתמשים בגרסה של ViewModel שקודמת לגרסה 2.5.0, אתם צריכים לספק factories מקבוצת משנה של מחלקות שמרחיבות את ViewModelProvider.Factory ומיישמות את הפונקציה create(Class<T>). בהתאם לתלות של ViewModel, צריך להרחיב מחלקה אחרת מתוך:
-
AndroidViewModelFactoryאם נדרשת הכיתהApplication. -
AbstractSavedStateViewModelFactoryאם צריך להעביר אתSavedStateHandleכתלות.
אם לא צריך את Application או SavedStateHandle, פשוט מאריכים מ-ViewModelProvider.Factory.
בדוגמה הבאה נעשה שימוש ב-AbstractSavedStateViewModelFactory עבור ViewModel שמקבל מאגר וסוג SavedStateHandle כתלות:
Kotlin
class MyViewModel(
private val myRepository: MyRepository,
private val savedStateHandle: SavedStateHandle
) : ViewModel() {
// ViewModel logic ...
// Define ViewModel factory in a companion object
companion object {
fun provideFactory(
myRepository: MyRepository,
owner: SavedStateRegistryOwner,
defaultArgs: Bundle? = null,
): AbstractSavedStateViewModelFactory =
object : AbstractSavedStateViewModelFactory(owner, defaultArgs) {
@Suppress("UNCHECKED_CAST")
override fun <T : ViewModel> create(
key: String,
modelClass: Class<T>,
handle: SavedStateHandle
): T {
return MyViewModel(myRepository, handle) as T
}
}
}
}
Java
import androidx.annotation.NonNull;
import androidx.lifecycle.AbstractSavedStateViewModelFactory;
import androidx.lifecycle.SavedStateHandle;
import androidx.lifecycle.ViewModel;
public class MyViewModel extends ViewModel {
public MyViewModel(
MyRepository myRepository,
SavedStateHandle savedStateHandle
) { /* Init ViewModel here */ }
}
public class MyViewModelFactory extends AbstractSavedStateViewModelFactory {
private final MyRepository myRepository;
public MyViewModelFactory(
MyRepository myRepository
) {
this.myRepository = myRepository;
}
@SuppressWarnings("unchecked")
@NonNull
@Override
protected <T extends ViewModel> T create(
@NonNull String key, @NonNull Class<T> modelClass, @NonNull SavedStateHandle handle
) {
return (T) new MyViewModel(myRepository, handle);
}
}
לאחר מכן, אפשר להשתמש ב-factory כדי לאחזר את ה-ViewModel:
Kotlin
import androidx.activity.viewModels
class MyActivity : AppCompatActivity() {
private val viewModel: MyViewModel by viewModels {
MyViewModel.provideFactory((application as MyApplication).myRepository, this)
}
// Rest of Activity code
}
Java
import androidx.appcompat.app.AppCompatActivity;
import androidx.lifecycle.ViewModelProvider;
public class MyActivity extends AppCompatActivity {
MyViewModel myViewModel = new ViewModelProvider(
this,
ViewModelProvider.Factory.from(MyViewModel.initializer)
).get(MyViewModel.class);
// Rest of Activity code
}
מומלץ בשבילך
- הערה: טקסט הקישור מוצג כש-JavaScript מושבת
- מודול Saved State ל-ViewModel
- שמירת מצבי ממשק המשתמש
- סקירה כללית של LiveData