نظرة عامة على ViewModel (طرق العرض)
المفاهيم والتنفيذ في Jetpack Compose
فئة ViewModel هي عنصر الاحتفاظ بالحالة على مستوى منطق النشاط التجاري أو الشاشة. تعرض هذه الطبقة الحالة لواجهة المستخدم وتغلف منطق النشاط التجاري ذي الصلة.
وتتمثّل ميزته الأساسية في أنّه يخزّن الحالة مؤقتًا ويحتفظ بها عند إجراء تغييرات في الإعدادات. وهذا يعني أنّه ليس على واجهة المستخدم جلب البيانات مرة أخرى عند التنقّل بين الأنشطة أو عند إجراء تغييرات في الإعدادات، مثل تدوير الشاشة.
مزايا ViewModel
البديل عن ViewModel هو فئة عادية تحتوي على البيانات التي تعرضها في واجهة المستخدم. ويمكن أن يصبح ذلك مشكلة عند التنقّل بين الأنشطة أو وجهات التنقّل. سيؤدي ذلك إلى إتلاف البيانات إذا لم يتم تخزينها باستخدام آلية حفظ حالة المثيل. توفّر ViewModel واجهة برمجة تطبيقات ملائمة لاستمرار البيانات، ما يحلّ هذه المشكلة.
تتمثّل الميزتان الرئيسيتان لفئة ViewModel في ما يلي:
- يتيح لك الاحتفاظ بحالة واجهة المستخدم.
- ويوفّر إمكانية الوصول إلى منطق النشاط التجاري.
النطاق
عند إنشاء مثيل من ViewModel، عليك تمرير عنصر ينفّذ واجهة
ViewModelStoreOwner. قد يكون هذا النوع وجهة تنقّل أو رسمًا بيانيًا للتنقّل أو نشاطًا أو جزءًا أو أي نوع آخر ينفّذ الواجهة. بعد ذلك، يتم تحديد نطاق ViewModel إلى Lifecycle الخاص بـ ViewModelStoreOwner. ويظل في الذاكرة إلى أن يختفي ViewModelStoreOwner نهائيًا.
تكون مجموعة من الفئات إما فئات فرعية مباشرة أو غير مباشرة من واجهة ViewModelStoreOwner. الفئات الفرعية المباشرة هي
ComponentActivity وFragment وNavBackStackEntry.
للاطّلاع على قائمة كاملة بالفئات الفرعية غير المباشرة، راجِع مرجع ViewModelStoreOwner.
تنفيذ ViewModel
في ما يلي مثال على تنفيذ ViewModel لشاشة تتيح للمستخدم رمي النرد.
Kotlin
data class DiceUiState(
val firstDieValue: Int? = null,
val secondDieValue: Int? = null,
val numberOfRolls: Int = 0,
)
class DiceRollViewModel : ViewModel() {
// Expose screen UI state
private val _uiState = MutableStateFlow(DiceUiState())
val uiState: StateFlow<DiceUiState> = _uiState.asStateFlow()
// Handle business logic
fun rollDice() {
_uiState.update { currentState ->
currentState.copy(
firstDieValue = Random.nextInt(from = 1, until = 7),
secondDieValue = Random.nextInt(from = 1, until = 7),
numberOfRolls = currentState.numberOfRolls + 1,
)
}
}
}
Java
public class DiceUiState {
private final Integer firstDieValue;
private final Integer secondDieValue;
private final int numberOfRolls;
// ...
}
public class DiceRollViewModel extends ViewModel {
private final MutableLiveData<DiceUiState> uiState =
new MutableLiveData(new DiceUiState(null, null, 0));
public LiveData<DiceUiState> getUiState() {
return uiState;
}
public void rollDice() {
Random random = new Random();
uiState.setValue(
new DiceUiState(
random.nextInt(7) + 1,
random.nextInt(7) + 1,
uiState.getValue().getNumberOfRolls() + 1
)
);
}
}
يمكنك بعد ذلك الوصول إلى ViewModel من نشاط على النحو التالي:
Kotlin
import androidx.activity.viewModels
class DiceRollActivity : AppCompatActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
// Create a ViewModel the first time the system calls an activity's onCreate() method.
// Re-created activities receive the same DiceRollViewModel instance created by the first activity.
// Use the 'by viewModels()' Kotlin property delegate
// from the activity-ktx artifact
val viewModel: DiceRollViewModel by viewModels()
lifecycleScope.launch {
repeatOnLifecycle(Lifecycle.State.STARTED) {
viewModel.uiState.collect {
// Update UI elements
}
}
}
}
}
Java
public class MyActivity extends AppCompatActivity {
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
// Create a ViewModel the first time the system calls an activity's onCreate() method.
// Re-created activities receive the same MyViewModel instance created by the first activity.
DiceRollViewModel model = new ViewModelProvider(this).get(DiceRollViewModel.class);
model.getUiState().observe(this, uiState -> {
// update UI
});
}
}
اقتراحات مخصصة لك
- ملاحظة: يتم عرض نص الرابط عندما تكون JavaScript غير مفعّلة.
- استخدام "كوروتينات" Kotlin مع المكوّنات التي تراعي مراحل النشاط
- حفظ حالات واجهة المستخدم
- تحميل البيانات المقسّمة إلى صفحات وعرضها