问题
I have been spending a lot of time trying to figure out why in the code below (towards the end), I get an error on ViewModelProvider(this). I also tried getActivity() instead of 'this', same issue. The error I get is "Cannot resolve constructor ..."
import androidx.fragment.app.Fragment;
import androidx.lifecycle.ViewModelProvider;
public class ItemSetupFragment extends Fragment {
@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
View view = inflater.inflate(R.layout.fragment_setup, container, false);
return view;
}
@Override
public void onViewCreated(@NonNull View view, Bundle savedInstanceState) {
super.onViewCreated(view, savedInstanceState);
ItemSetupFragmentModel model = new ViewModelProvider(this).get(ItemSetupFragmentModel.class);
model.getKids().observe(this, users -> {
// update UI
});
}
}
回答1:
Firstly you need to use the latest version of lifecycle extension. It should be:
implementation 'androidx.lifecycle:lifecycle-extensions:2.2.0'
implementation "androidx.lifecycle:lifecycle-viewmodel:2.2.0"
or any updated version.
Then you should use requireActivity()
instead of getActivity()
. This way you will ensure that the activity is attached an not getting a NullPointerException
.
ItemSetupFragmentModel model = new ViewModelProvider(requireActivity()).get(ItemSetupFragmentModel.class);
回答2:
You aren't using the latest library release in which the ViewModelProvider(@NonNull ViewModelStoreOwner owner)
constructor was included. You are seeing the latest docs but not using the latest library version of ViewModel
.
You need to use
implementation 'androidx.lifecycle:lifecycle-viewmodel:2.2.0' // For Java
or
implementation 'androidx.lifecycle:lifecycle-viewmodel-ktx:2.2.0' // For kotlin extension
回答3:
You should instantiate your viewModel by :
ItemSetupFragmentModel model = ViewModelProviders.of(this).get(ItemSetupFragmentModel.class);
回答4:
The cleanest implementation must use Kotlin for its advanced functions. You can either create this kotlin code in a separate Kclass or leave this answer for future users that want to know how to do this in Kotlin. Basically we are initialising the ViewModel by lazy like this:
Make sure you have this dependency:
implementation "androidx.fragment:fragment-ktx:1.2.0"
Create this helper function that accesses an internal fragment-ktx method that allows yo to create a ViewModel instance by lazy:
@MainThread
inline fun <reified VM : ViewModel> Fragment.fragmentViewModel() =
createViewModelLazy(
VM::class,
{ this.viewModelStore },
{ ViewModelFactory(Database.getDatabase(requireContext().applicationContext)) }
)
Now create a ViewModelFactory using this official java example:
https://github.com/android/architecture-components-samples/blob/master/BasicRxJavaSample/app/src/main/java/com/example/android/observability/ui/ViewModelFactory.java
Or, here is the Kotlin variant:
class ViewModelFactory(private val database: Database?) : ViewModelProvider.Factory {
override fun <T : ViewModel> create(modelClass: Class<T>): T {
requireNotNull(database) { "Database must not be null" }
return when {
modelClass.isAssignableFrom(ItemSetupFragmentModel::class.java) -> {
ItemSetupFragmentModel() as T
}
else -> {
throw IllegalArgumentException("Unknown ViewModel class")
}
}
}
}
And now go inside your fragment and simply initialise your ViewModel like this
class ItemSetupFragment : Fragment() {
private val model by viewModel<ItemSetupFragmentModel>()
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState)
model.getKids().observe(this, users -> {
// update UI
});
}
}
Hope this helps!
来源:https://stackoverflow.com/questions/60070233/cannot-resolve-viewmodelprovider-construction-in-a-fragment