java.lang.RuntimeException:
Unable to start activity ComponentInfo{ir.orangehat.movieinfo/ir.orangehat.movieinfo.application.home.HomeActivity}: java.lang.RuntimeException:
Cannot create an instance of class ir.orangehat.movieinfo.application.home.HomeViewModel
public class HomeViewModel extends AndroidViewModel {
private MovieRepository movieRepository;
public HomeViewModel(@NonNull Application application, Context context, LifecycleOwner lifecycleOwner) {
super(application);
movieRepository = new MovieRepository(lifecycleOwner, context);
}
LiveData<List<Movie>> getMovies() {
return movieRepository.getMovies();
}}
public class MovieRepository extends BaseRepository {
private LifecycleOwner lifecycleOwner;
private MovieApi movieApi;
private MovieDatabaseHelper movieDatabaseHelper;
public MovieRepository(LifecycleOwner lifecycleOwner, Context context) {
this.lifecycleOwner = lifecycleOwner;
movieApi = getRetrofitHelper().getService(MovieApi.class);
movieDatabaseHelper = new MovieDatabaseHelper(context);
}
public LiveData<List<Movie>> getMovies() {
LiveData<List<Movie>> moviesLiveData = movieApi.getMovieList();
moviesLiveData.observe(lifecycleOwner, new Observer<List<Movie>>() {
@Override
public void onChanged(@Nullable List<Movie> movieArrayList) {
movieDatabaseHelper.Save(movieArrayList);
}
});
return movieDatabaseHelper.getAll();
} }
public class HomeActivity extends AppCompatActivity {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
// the error is here
HomeViewModel homeViewModel = ViewModelProviders.of(this).get(HomeViewModel.class);
homeViewModel.getMovies().observe(HomeActivity.this, new Observer<List<Movie>>() {
@Override
public void onChanged(@Nullable List<Movie> movieArrayList) {
String str = null;
if (movieArrayList != null) {
str = Arrays.toString(movieArrayList.toArray());
}
Log.e("movies", str);
}
});
}
}
答案 0 :(得分:10)
引用the documentation for AndroidViewModel
:
子类必须具有接受Application作为唯一参数的构造函数。
您的构造函数不符合该要求。
或者:
从Context context
或
LifecycleOwner lifecycleOwner
和HomeViewModel
构造函数参数
创建可构建HomeViewModel
个实例的a ViewModelProvider.Factory
,并将该工厂与ViewModelProviders.of()
一起使用
答案 1 :(得分:1)
如果您正在使用Kotlin,并且需要在ViewModel构造函数中注入一个依赖项以像存储库一样工作以获取数据(与我们使用Presenter层的方式相同),则需要执行以下操作。
让我们说我们有一个ViewModel,需要将UseCase / Interactor注入到构造函数中才能从中获取数据。
class MainViewModel(private val itemList:ItemListUseCase):ViewModel() {
...
}
当我们尝试在 Activity / Fragment 中实例化此ViewModel时,我们倾向于这样做
片段示例
class MainFragment : Fragment() {
private lateinit var mainViewModel: MainViewModel
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
mainViewModel = requireActivity().run {
ViewModelProviders.of(this).get(MainViewModel::class.java)
}
...
}
}
当我们尝试运行代码时,它将以RuntimeException
java.lang.RuntimeException:无法创建类的实例 com.gaston.example.viewmodel.MainViewModel ...原因: java.lang.InstantiationException: java.lang.Class 没有零参数构造函数
这是因为实例化ItemListUseCase
时没有注入ViewModel
出现的第一件事是尝试直接从.get()
的{{1}}方法注入它
ViewModelProviders
但是,如果这样做,我们也会收到相同的错误。
我们需要了解的是
ViewModelProviders.of(this).get(MainViewModel(ItemListUseCase())::class.java)
ViewModelProviders.of(this).get(MainViewModel::class.java)
试图创建MainViewModel的实例,却不知道其构造函数内部需要依赖项。
要解决此问题,我们需要让ViewModelProviders.of()
知道我们要注入的依赖项。
为此,我们需要创建一个类来确保该ViewModel的实例需要实例化依赖项。
此类称为Factory ViewModel类,因为它将使用需要工作的依赖关系构造我们的ViewModel,然后让ViewModelProviers.of()
知道我们需要传递给ViewModelProviers.of()
的依赖关系< / p>
.get(MainViewModel::class.java)
现在,我们可以告诉ViewModelProviers.of()它需要一个class ViewModelFactory(val requestItemData: ItemListUseCase):ViewModelProvider.Factory {
override fun <T : ViewModel?> create(modelClass: Class<T>): T {
return modelClass.getConstructor(ItemListUseCase::class.java).newInstance(requestItemData)
}
}
的实例来实例化ItemListUseCase::class.java
MainViewModel(ItemListuseCase())
请注意,我没有将任何参数传递给override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
mainViewModel = requireActivity().run {
ViewModelProviders.of(this,ViewModelFactory(ItemListUseCase())).get(MainViewModel::class.java)
}
}
,因为我们的工厂将负责将这些参数注入到构造函数中。
最后,如果要避免使用Factory类,则始终可以使用Dagger注入依赖项,而不必担心ViewModel Factory类。
答案 2 :(得分:0)
如果它可以帮助某人。就我而言,CommonsWare告诉的一切都是正确的,但是,我忘记注入AppComponennt。
@Override
protected void onCreate(@Nullable Bundle savedInstanceState) {
// this line was missing
((BaseApplication) getApplication()).getAppComponent().inject(this);
super.onCreate(savedInstanceState);
}
答案 3 :(得分:0)
In HomeViewModel class need to extend ViewModel class.
public class MovieListViewModel extends ViewModel {
private MutableLiveData<MovieModel> data;
private MovieRepository movieModel;
public MovieListViewModel() {
movieModel = new MovieRepository();
}
public void init() {
if (this.data != null) {
// ViewModel is created per Fragment so
// we know the userId won't change
return;
}
data = movieModel.getMovies();
}
public MutableLiveData<MovieModel> getMovies() {
return this.data;
}
}
答案 4 :(得分:0)
尝试添加此内容:
private LiveData<Section[]> movies;
然后,更改此内容:
LiveData<List<Movie>> getMovies() {
if(movies==null)
movies= movieRepository.getMovies();
return movies;
}
对我有用。
答案 5 :(得分:0)
正如其他答案中所述,ViewModelProviders无法注入ViewModel构造函数中所需的对象。
如果您需要在没有任何工厂的情况下快速设置ViewModel 丑陋,则可以使用Dagger2在创建的getYourViewModel()
中创建DaggerActivityComponent
方法,同时将它们通过@Provides批注提供给构造函数的对象。然后只需将此字段添加到您的活动中即可:
@Inject
lateinit var viewmodel: YourViewModel
并将其注入OnCreate()
中,就是这样。 NB :请谨慎使用笨重的ViewModel和慢速的ViewModel。
答案 6 :(得分:-1)
基于this answer,您可以执行此操作
class MvpApp : Application(){
companion object {
lateinit var application: Application
}
override fun onCreate() {
super.onCreate()
application = this
}
}
然后:
class ProfileViewModel: AndroidViewModel(MvpApp.application) {}