【问题标题】:How to pass data from activity or fragment to viewmodel?如何将数据从活动或片段传递到视图模型?
【发布时间】:2020-03-28 15:01:51
【问题描述】:

我正在创建一个项目,在该项目中我使用 themoviedb api 来获取数据。为此,我使用 MVVM 架构。从 MovieListFragment ,我想将诸如流行、top_rated 之类的类别传递给 MovieViewModel 以相应地过滤电影,但我得到的是空值。

这里是 MovieListFragment 类:-

public class MovieListFragment extends Fragment {

    private MovieViewModel movieViewModel;
    private static final String BASE_URL = "https://api.themoviedb.org";
    private static final String API_KEY = "API_KEY";
    private String category;

    private GridView gridView;

    @Override
    public View onCreateView(LayoutInflater inflater, ViewGroup container,
                             Bundle savedInstanceState) {
        View rootView = inflater.inflate(R.layout.fragment_movie_list, container, false);
        gridView = rootView.findViewById(R.id.images_grid_view);

        movieViewModel = ViewModelProviders.of(this).get(MovieViewModel.class);
        movieViewModel.setCategory(category);  // from here i am passing value
        movieViewModel.getMoviesRepository().observe(getActivity(), new Observer<MovieResults>() {  // error line no :- 76
                @Override
                public void onChanged(MovieResults movieResults) {
                    final List<MovieResults.ResultsBean> listOfMovies = movieResults.getResults();  // error line no :- 79

                    MovieListAdapter mAdapter = new MovieListAdapter(getContext(), listOfMovies);
                    gridView.setAdapter(mAdapter);
                    gridView.setOnItemClickListener(new AdapterView.OnItemClickListener() {
                        @Override
                        public void onItemClick(AdapterView<?> parent, View view, int position, long id) {
                            mCallback.onImageSelected(position, listOfMovies);
                        }
                    });
                }
            });
        return rootView;
    }

    public void setCategory(String category) {
        this.category = category;
    }
}

这是 MovieViewModel 类:-

public class MovieViewModel extends AndroidViewModel {
    private String category;
    private static final String API_KEY = "api_key";
    private MovieRepository repository;
    private MutableLiveData<MovieResults> listOfMovies;

    public MovieViewModel(@NonNull Application application) {
        super(application);
        Log.d("MovieViewModel", category); // but here i am getting null value
        listOfMovies = repository.getListOfMovies(category, API_KEY);
    }

    public MutableLiveData<MovieResults> getMoviesRepository() {
        return listOfMovies;
    }

    public void setCategory(String category) {
        this.category = category;
    }
}

我收到这样的错误:-

java.lang.NullPointerException: Attempt to invoke virtual method 'java.util.List com.mountblue.moviesapp.entity.MovieResults.getResults()' on a null object reference
        at com.mountblue.moviesapp.fragment.MovieListFragment$2.onChanged(MovieListFragment.java:79)
        at com.mountblue.moviesapp.fragment.MovieListFragment$2.onChanged(MovieListFragment.java:76)

【问题讨论】:

  • 我不知道为什么它不适用于您的情况,但您的问题是我问题的答案。它在我的项目中运行良好。谢谢

标签: java android android-studio mvvm android-mvvm


【解决方案1】:

由于Category是在setter之前被MovieViewModel的构造函数读取的,所以一直为null。

类别作为方法参数呢?

public class MovieViewModel extends AndroidViewModel {

    private static final String API_KEY = "api_key";
    private MovieRepository repository;
    private MutableLiveData<MovieResults> listOfMovies = new MutableLiveData<MovieResults>();

    public MovieViewModel(@NonNull Application application) {
        super(application);
    }

    public MutableLiveData<MovieResults> getMoviesRepository(category) {
        loadData(category);
        return listOfMovies;
    }

    private void loadData(category) {
        // Do an asynchronous operation to fetch MovieResults.
        repository.getListOfMovies(category, API_KEY);

        ...
        // Receive asynchronous result in callback

        // Post the result after getting the asynchronous result.
        listOfMovies.postValue(response)
    }
}

如需更详细的实现,需要一个存储库类。

文件: https://developer.android.com/topic/libraries/architecture/viewmodel

【讨论】:

    【解决方案2】:

    您必须创建视图模型工厂才能将数据从活动或片段传递到视图模型。您可以通过here 参考。

    【讨论】:

      【解决方案3】:

      如果您在movieViewModel.setCategory(category); 行中获得字符串categorynull 值,则表示MovieListFragment 的字段category 为空。

      尝试检查您是否在fragment 上调用了setCategory(String category) 方法。

      如果不是这样,请详细说明错误。例如。它发生在哪一行等。

      【讨论】:

        【解决方案4】:

        在 MovieListFragment 类中:

        先删除这一行:movieViewModel.setCategory(category);

        并在此处传递“类别”:movieViewModel.getMoviesRepository(category) 如下代码:

        movieViewModel.getMoviesRepository(category).observe(getActivity(), new Observer<MovieResults>() {  // error line no :- 76
                    @Override
                    public void onChanged(MovieResults movieResults) {
                        final List<MovieResults.ResultsBean> listOfMovies = movieResults.getResults();  // error line no :- 79
        
                        MovieListAdapter mAdapter = new MovieListAdapter(getContext(), listOfMovies);
                        gridView.setAdapter(mAdapter);
                        gridView.setOnItemClickListener(new AdapterView.OnItemClickListener() {
                            @Override
                            public void onItemClick(AdapterView<?> parent, View view, int position, long id) {
                                mCallback.onImageSelected(position, listOfMovies);
                            }
                        });
                    }
                });
        

        在 MovieViewModel 类中:

        将这一行移到 getMoviesRepository(String category) listOfMovies = repository.getListOfMovies(category, API_KEY);

        然后像这样从MovieViewModel 类中删除类别变量和setCategory() 方法:

        public class MovieViewModel extends AndroidViewModel {
            
            private static final String API_KEY = "api_key";
            private MovieRepository repository;
            private MutableLiveData<MovieResults> listOfMovies;
        
            public MovieViewModel(@NonNull Application application) {
                super(application);
                
            }
        
            public MutableLiveData<MovieResults> getMoviesRepository(String category) {
                Log.d("MovieViewModel", category); // but here i am getting null value
                listOfMovies = repository.getListOfMovies(category, API_KEY);
                return listOfMovies;
            }
        
        }
        

        【讨论】:

        • repository 是如何创建的?
        • repository 类就像一个模型类,但它使用DAO接口获取和设置数据到离线房间数据库,也可以从在线服务器获取和设置数据。我找不到一个好的简单的 java 示例,但在 GitHub 上看到了这个简单的项目。他们使用远程和本地存储库github.com/segunfamisa/android-mvvm-sample/tree/master/app/src/…
        • 感谢您的详细解答!是的,我知道它可以是 Room 数据库。我的意思是,它是如何创建的(例如repository = new ...)?因为我们没有直接在MovieViewModel 内部传递repository(而且我看不到它是如何创建的)。不是你代码的问题,而是作者和所有回复者的问题。
        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 2023-03-11
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2021-07-23
        • 1970-01-01
        相关资源
        最近更新 更多