提问者:小点点

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


我使用MVVM,改造,LiveData在我的项目,但我得到这个错误之前,我看到这些链接

  • 无法创建自定义ViewModel的实例
  • 无法创建ViewModel类的实例
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);
            }
        });
    }
}

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


共3个答案

匿名用户

引用AndroidViewModel的留档:

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

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

要么:

>

  • 从您的HomeViewModel中删除Context上下文LifeycleOwner lifeycleOwner构造函数参数,或

    创建一个可以构建您的HomeViewModel实例的ViewModelProvider. Factory,并将该工厂与ViewModelProviders.of()一起使用

  • 匿名用户

    如果您正在使用静态编程语言,并且您需要在ViewModel构造函数中注入依赖项以使用存储库来获取数据(与我们使用Presenter层的方式相同),您将需要执行以下操作。

    假设我们有一个ViewModel,它需要在构造函数中注入一个UseCase/Intertor来获取数据。

    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 {
                    ViewModelProvider(this).get(MainViewModel::class.java)
                }
              ...
            }
    }
    

    当我们尝试运行代码时,它会因RuntimeException而崩溃

    java. lang.RuntimeException:无法创建com.gaston.example.viewmodel.MainViewModel类的实例…由:java.lang.InstantiationException:java.lang.Class引起

    这是因为当我们实例化我们的ViewModel时,我们没有注入ItemListUseCase

    首先出现的是尝试直接从ViewModelProvider. get()方法注入它

    ViewModelProvider(this).get(MainViewModel(ItemListUseCase()))
    

    但是如果我们这样做,我们也会得到同样的错误。

    我们需要了解的是

    ViewModelProvider(this).get(MainViewModel::class.java)
    

    ViewModelProvider()正在尝试执行MainViewModel的实例,而不知道它需要在其构造函数中的依赖项。

    要解决此问题,我们需要让ViewModelProvier()知道我们要注入的依赖项。

    为此,我们需要创建一个类,以确保该ViewModel的实例需要实例化依赖项。

    这个类被称为Factory ViewModel类,因为它将用它需要工作的依赖项构造我们的ViewModel,然后它将让ViewModelProvier()知道我们需要将哪个依赖项传递给. get(MainViewModel::class.java)

    class ViewModelFactory(val requestItemData: ItemListUseCase):ViewModelProvider.Factory {
    
        override fun <T : ViewModel?> create(modelClass: Class<T>): T {
            return modelClass.getConstructor(ItemListUseCase::class.java).newInstance(requestItemData)
        }
    }
    

    现在,我们可以告诉ViewModelProviers. of()它需要一个ItemListUseCas的实例e::class.java来实例化MainViewModel(ItemListuseCase())

    override fun onCreate(savedInstanceState: Bundle?) {
            super.onCreate(savedInstanceState)
    
            mainViewModel = requireActivity().run {
                ViewModelProvider(this,ViewModelFactory(ItemListUseCase())).get(MainViewModel::class.java)
            }
    
        }
    

    请注意,我没有将任何参数传递给. get(MainViewModel::class.java),因为我们的工厂将负责将这些参数注入到我们的构造函数中。

    最后,如果您想避免Factory类,您可以始终使用Dagger注入您的依赖项,而无需担心ViewModel Factory类。

    匿名用户

    尝试添加这个:

    private LiveData<Section[]> movies;
    

    然后,改变这个:

    LiveData<List<Movie>> getMovies() {
        if(movies==null)
            movies= movieRepository.getMovies();
        return movies;
    }
    

    它对我有用。