How to get a ViewModel?
Asked Answered
B

6

3

I just want to get a reference in my Fragment (extends Fragment) to my ViewModel.class (extends from AndroidViewModel). This is how it is described everywhere:

UserModel userModel = ViewModelProviders.of(getActivity()).get(UserModel.class);

description on Android Developer

..., but ViewModelProviders is deprecated since long ago.

*This class was deprecated in API level 1.1.0. *

I can't import the class with: android.arch.lifecycle.[ViewModelProviders]

it just offers ViewModelProvider and other stuff.


How am I able to get an instance of my UserModel.class?

Blazonry answered 10/7, 2018 at 12:7 Comment(2)
where did you find *This class was deprecated in API level 1.1.0. *?Mulct
@MaxAves developer.android.com/reference/androidx/lifecycle/…Blazonry
H
2

but ViewModelProviders is deprecated since long ago

ViewModelProviders is not deprecated. So, use ViewModelProviders:

ViewModelProviders.of(yourFragment).get(UserModel.class)

There are pieces of ViewModelProviders that are deprecated, such as its constructor, but the class overall is not.

UPDATE: 2020-05-28 Now ViewModelProviders is deprecated. In Kotlin, use by viewModels() and related property delegates. In Java, use new ViewModelProvider(...).get(UserModel.class) (for various values of ... depending on the scope of those viewmodels).

Heritor answered 10/7, 2018 at 12:10 Comment(4)
It is pointed out red. Should I extend my Fragment from another class?Blazonry
or should I add a dependency?Blazonry
@fabi: "It is pointed out red" -- you are missing the import statement. You will also need the android.arch.lifecycle:extensions dependency, as is noted in the ViewModelProviders JavaDocs.Heritor
ViewModelProviders is deprecatedLisettelisha
U
3

Using Kotlin with the latest Android architecture components you should use the by viewModels() Kotlin property delegate like so:

class YourFragment : Fragment() {
   private val viewModel by viewModels<YourViewModel>()
}

More info here

Uretic answered 20/4, 2020 at 11:17 Comment(0)
H
2

but ViewModelProviders is deprecated since long ago

ViewModelProviders is not deprecated. So, use ViewModelProviders:

ViewModelProviders.of(yourFragment).get(UserModel.class)

There are pieces of ViewModelProviders that are deprecated, such as its constructor, but the class overall is not.

UPDATE: 2020-05-28 Now ViewModelProviders is deprecated. In Kotlin, use by viewModels() and related property delegates. In Java, use new ViewModelProvider(...).get(UserModel.class) (for various values of ... depending on the scope of those viewmodels).

Heritor answered 10/7, 2018 at 12:10 Comment(4)
It is pointed out red. Should I extend my Fragment from another class?Blazonry
or should I add a dependency?Blazonry
@fabi: "It is pointed out red" -- you are missing the import statement. You will also need the android.arch.lifecycle:extensions dependency, as is noted in the ViewModelProviders JavaDocs.Heritor
ViewModelProviders is deprecatedLisettelisha
V
1

Here's how to write a ViewModel

public class MyViewModel extends ViewModel {
private MutableLiveData<List<User>> users;
public LiveData<List<User>> getUsers() {
    if (users == null) {
        users = new MutableLiveData<List<User>>();
        loadUsers();
    }
    return users;
}

private void loadUsers() {
    // Do an asynchronous operation to fetch users.
}
}

And then to use it in your actctivity do something like this

public class MyActivity extends AppCompatActivity {
public void onCreate(Bundle 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.

    MyViewModel model = ViewModelProviders.of(this).get(MyViewModel.class);
    model.getUsers().observe(this, users -> {
        // update UI
    });
}
}
Venous answered 17/2, 2019 at 7:37 Comment(0)
L
0

The class ViewModelProviders is deprecated! Use ViewModelProvider understood.

MyViewModel viewModel = new ViewModelProvider(this).get(MyViewModel.class);

Happy coding :)

Lisettelisha answered 28/5, 2020 at 6:28 Comment(0)
E
0

After digging around I solved my similiar problem by adding the following method to my Activities:

protected final <T extends ViewModel> T obtainViewModel(@NonNull AppCompatActivity activity, @NonNull Class<T> modelClass) {
    ViewModelProvider.AndroidViewModelFactory factory = ViewModelProvider.AndroidViewModelFactory.getInstance(activity.getApplication());
    return new ViewModelProvider(activity, factory).get(modelClass);
}

And then I did this in my Fragments:

protected final <T extends ViewModel> T obtainFragmentViewModel(@NonNull FragmentActivity fragment, @NonNull Class<T> modelClass) {
    ViewModelProvider.AndroidViewModelFactory factory = ViewModelProvider.AndroidViewModelFactory.getInstance(fragment.getApplication());
    return new ViewModelProvider(fragment, factory).get(modelClass);
}

I already had some abstract super classes for menu purposes so I hid the methods away there so I don't have to repeat it in every activity. That's why they are protected. I believe they could be private if you put them in every activity or fragment that you need them in.

To be as clear as possible I would then call the methods to assign my view model in onCreate() in my activity and it would look something like this

private MyViewModel myViewModel;

@Override
public void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    myViewModel = obtainViewModel(this, MyViewModel.class);
}

or in fragment

private MyViewModel myViewModel;

@Override
public void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    if (getActivity() != null) {
        myViewModel = obtainFragmentViewModel(getActivity(), MyViewModel.class);
    }
}
Enzootic answered 14/6, 2020 at 19:37 Comment(0)
P
0

Kotlin version of BeirDav's answer is

val vm = ViewModelProvider(requireActivity()).get(MyViewModel::class.java)
Privily answered 4/2, 2021 at 14:46 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.