‫ViewModel Scoping APIs (Views)   בארגז הכלים Android Jetpack.

מושגים ויישום ב-Jetpack פיתוח נייטיב

היקף הוא המפתח לשימוש יעיל ב-ViewModels. כל ViewModel מוגדר בהיקף של אובייקט שמטמיע את הממשק ViewModelStoreOwner. יש כמה ממשקי API שמאפשרים לנהל בקלות רבה יותר את ההיקף של ViewModels.

השיטה ViewModelProvider.get() מאפשרת לקבל מופע של ViewModel בהיקף של כל ViewModelStoreOwner. למשתמשי Kotlin, יש פונקציות הרחבה שונות שזמינות לתרחישי השימוש הנפוצים ביותר. כל ההטמעות של פונקציות ההרחבה של Kotlin משתמשות ב-ViewModelProvider API מתחת לפני השטח.

‫ViewModels בהיקף של ViewModelStoreOwner הקרוב ביותר

אפשר להגדיר את ה-ViewModel בהיקף של Activity,‏ Fragment או יעד של תרשים ניווט. הפונקציות של התוסף viewModels() שסופקו על ידי הספריות Activity,‏ Fragment ו-Navigation מאפשרות לקבל מופע של ViewModel בהיקף של ViewModelStoreOwner הכי קרוב.

צפיות

import androidx.activity.viewModels

class MyActivity : AppCompatActivity() {
    // ViewModel API available in activity.activity-ktx
    // The ViewModel is scoped to `this` Activity
    val viewModel: MyViewModel by viewModels()
}

import androidx.fragment.app.viewModels

class MyFragment : Fragment() {
    // ViewModel API available in fragment.fragment-ktx
    // The ViewModel is scoped to `this` Fragment
    val viewModel: MyViewModel by viewModels()
}

צפיות

import androidx.lifecycle.ViewModelProvider;

public class MyActivity extends AppCompatActivity {
    // The ViewModel is scoped to `this` Activity
    MyViewModel viewModel = new ViewModelProvider(this).get(MyViewModel.class);
}

public class MyFragment extends Fragment {
    // The ViewModel is scoped to `this` Fragment
    MyViewModel viewModel = new ViewModelProvider(this).get(MyViewModel.class);
}

‫ViewModels בהיקף של כל ViewModelStoreOwner

הפונקציות ComponentActivity.viewModels() ו-Fragment.viewModels() בתצוגת המערכת מקבלות פרמטר אופציונלי ownerProducer שאפשר להשתמש בו כדי לציין את ViewModelStoreOwner שאליו מוגדרת ההיקף של המופע של ViewModel. בדוגמה הבאה אפשר לראות איך מקבלים מופע של ViewModel בהיקף של קטע האב:

צפיות

import androidx.fragment.app.viewModels

class MyFragment : Fragment() {

    // ViewModel API available in fragment.fragment-ktx
    // The ViewModel is scoped to the parent of `this` Fragment
    val viewModel: SharedViewModel by viewModels(
        ownerProducer = { requireParentFragment() }
    )
}

צפיות

import androidx.lifecycle.ViewModelProvider;

public class MyFragment extends Fragment {

    SharedViewModel viewModel;

    @Override
    public void onViewCreated(View view, Bundle savedInstanceState) {
        // The ViewModel is scoped to the parent of `this` Fragment
        viewModel = new ViewModelProvider(requireParentFragment())
            .get(SharedViewModel.class);
    }
}

תרחיש נפוץ לדוגמה הוא קבלת ViewModel בהיקף Activity מ-Fragment. כשעושים את זה, אפשר להשתמש בפונקציית התוסף activityViewModels() Views. אם אתם לא משתמשים ב-Views וב-Kotlin, אתם יכולים להשתמש באותם ממשקי API שצוינו למעלה, ולהעביר את הבעלים הנכון.

צפיות

import androidx.fragment.app.activityViewModels

class MyFragment : Fragment() {

    // ViewModel API available in fragment.fragment-ktx
    // The ViewModel is scoped to the host Activity
    val viewModel: SharedViewModel by activityViewModels()
}

צפיות

import androidx.lifecycle.ViewModelProvider;

public class MyFragment extends Fragment {

    SharedViewModel viewModel;

    @Override
    public void onViewCreated(View view, Bundle savedInstanceState) {
        // The ViewModel is scoped to the host Activity
        viewModel = new ViewModelProvider(requireActivity())
            .get(SharedViewModel.class);
    }
}

‫ViewModels בהיקף של תרשים הניווט

גרפים של ניווט הם גם בעלים של מאגרי ViewModel. אם משתמשים ב-Navigation Fragment, אפשר לקבל מופע של ViewModel בהיקף של גרף ניווט באמצעות פונקציית ההרחבה navGraphViewModels(graphId) Views.

צפיות

import androidx.navigation.navGraphViewModels

class MyFragment : Fragment() {

    // ViewModel API available in navigation.navigation-fragment
    // The ViewModel is scoped to the `nav_graph` Navigation graph
    val viewModel: SharedViewModel by navGraphViewModels(R.id.nav_graph)

    // Equivalent navGraphViewModels code using the viewModels API
    val viewModel: SharedViewModel by viewModels(
        { findNavController().getBackStackEntry(R.id.nav_graph) }
    )
}

צפיות

import androidx.lifecycle.ViewModelProvider;

public class MyFragment extends Fragment {

    SharedViewModel viewModel;

    @Override
    public void onViewCreated(View view, Bundle savedInstanceState) {
        NavController navController = NavHostFragment.findNavController(this);
        NavBackStackEntry backStackEntry = navController.getBackStackEntry(R.id.my_graph);

        // The ViewModel is scoped to the `nav_graph` Navigation graph
        viewModel = new ViewModelProvider(backStackEntry).get(SharedViewModel.class);
    }
}

אם אתם משתמשים ב-Hilt בנוסף ל-Jetpack Navigation, אתם יכולים להשתמש ב-API‏ hiltNavGraphViewModels(graphId) באופן הבא.

צפיות

import androidx.hilt.navigation.fragment.hiltNavGraphViewModels

class MyFragment : Fragment() {

    // ViewModel API available in hilt.hilt-navigation-fragment
    // The ViewModel is scoped to the `nav_graph` Navigation graph
    // and is provided using the Hilt-generated ViewModel factory
    val viewModel: SharedViewModel by hiltNavGraphViewModels(R.id.nav_graph)
}

צפיות

import androidx.hilt.navigation.HiltViewModelFactory;
import androidx.lifecycle.ViewModelProvider;

public class MyFragment extends Fragment {

    SharedViewModel viewModel;

    @Override
    public void onViewCreated(View view, Bundle savedInstanceState) {
        NavController navController = NavHostFragment.findNavController(this);
        NavBackStackEntry backStackEntry = navController.getBackStackEntry(R.id.my_graph);

        // The ViewModel is scoped to the `nav_graph` Navigation graph
        // and is provided using the Hilt-generated ViewModel factory
        viewModel = new ViewModelProvider(
            backStackEntry,
            HiltViewModelFactory.create(getContext(), backStackEntry)
        ).get(SharedViewModel.class);
    }
}