3

I am creating a project in which i am using themoviedb api to fetch data. For this I am using MVVM architecture. From MovieListFragment , I want to pass category such as popular, top_rated to MovieViewModel for filtering the movies accordingly , but there i am getting null value.

Here is MovieListFragment class :-

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

Here is MovieViewModel class :-

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

I am getting error like this :-

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)
Rockers Devil
  • 31
  • 1
  • 1
  • 3

3 Answers3

1

Since the Category is read by the constructor of MovieViewModel before the setter, it is always null.

What about category as method arguments?

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

For a more detailed implementation, need a repository class.

Documents: https://developer.android.com/topic/libraries/architecture/viewmodel

ysys
  • 82
  • 4
0

If you are getting null value for the string category in line movieViewModel.setCategory(category);, it means the field category of MovieListFragment is null.

Try checking if you have invoked the setCategory(String category) method on the fragment.

If that's not the case, please elaborate on the error. E.g. on which line it occurs etc.

tykimseoul
  • 86
  • 4
0

In MovieListFragment class:

First delete this line: movieViewModel.setCategory(category);

And pass "category" here: movieViewModel.getMoviesRepository(category) like code below:

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

In MovieViewModel class:

Move this line inside getMoviesRepository(String category) listOfMovies = repository.getListOfMovies(category, API_KEY);

And just remove category variable and setCategory() method from MovieViewModel class like this:

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

}
Brian Tompsett - 汤莱恩
  • 5,753
  • 72
  • 57
  • 129
Bonnjalal
  • 76
  • 4
  • How `repository` is created? – CoolMind Mar 30 '21 at 10:43
  • repository class just like a model class, but it gets and sets data to an offline room database using the DAO interface, and can get and set data also from an online server. I can't find a good and simple java example but see this simple project in GitHub. they use a remote and local repository https://github.com/segunfamisa/android-mvvm-sample/tree/master/app/src/main/java/com/segunfamisa/sample/mvvm/data/repository – Bonnjalal Mar 31 '21 at 16:32
  • Thank you for a detailed answer! Yes, I understand that it can be a Room database. I meant, how was it created (like `repository = new ...`)? Because we don't pass `repository` inside `MovieViewModel` directly (and I don't see, how it is created). It's not a problem of your code, but the author and all repliers. – CoolMind Mar 31 '21 at 16:39