无法创建ViewModel类的实例(无法启动活动ComponentInfo)

时间:2018-02-04 07:08:20

标签: android mvvm android-architecture-components android-viewmodel

我在我的项目中使用MVVM,Retrofit,LiveData但是在我看到这些链接之前我得到了这个错误

错误

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

这是我的ViewModel,我认为问题出在我的构造函数

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);
        }
    });
}

}

我应该在我的项目和自定义工厂中使用Dagger吗?

7 个答案:

答案 0 :(得分:10)

引用the documentation for AndroidViewModel

  

子类必须具有接受Application作为唯一参数的构造函数。

您的构造函数不符合该要求。

或者:

  • Context context

  • 中删除LifecycleOwner lifecycleOwnerHomeViewModel构造函数参数
  • 创建可构建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;
        }
    }

https://github.com/kamydeep00178/androidMvvm可以单独查看完整示例

答案 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) {}