How to reset MutableLiveData list to display new data when using setOnClickListner?

Viewed 162

So I have been trying for quite some time to add a search functionality for my app using TMDB API. What I have managed to do so far is to be able to search for a movie only the first time, so here's the problem when I am trying to search for a movie for the second time it will keep showing me the old movie list from the first search results, never updating the list accordingly to the search.

For example, i searched for a spiderman movie, it will show me every movie that has the keyword spiderman in it, and then when i try to search again for a different movie with a different keyword it will keep showing me the results from spiderman search, so is there any way to reset MutableLiveData list on every setOnClickListner, so I ll be able to search and display new movies on every search?.

Thank you in advance.

Here are the classes:

public interface SearchMovieService {

    @GET("search/movie?api_key=&language=en-US&page=1&include_adult=false")
    Call<MovieResponse> getMoviesWithSearching(@Query("query") String query);
}
public class SearchAPIManager {

    Retrofit retrofit =
            new Retrofit
                    .Builder()
                    .baseUrl("https://api.themoviedb.org/3/")
                    .addConverterFactory(GsonConverterFactory.create())
                    .build();

    private final SearchMovieService searchMovieService = retrofit.create(SearchMovieService.class);

    public void getMoviesWithSearching(MutableLiveData<List<Movie>> moviesLiveData, String query){

        Call<MovieResponse> movieHTTPRequest = searchMovieService.getMoviesWithSearching(query);
        movieHTTPRequest.enqueue(new Callback<MovieResponse>() {
            @Override
            public void onResponse(Call<MovieResponse> call, Response<MovieResponse> response) {
                MovieResponse movieResponse = response.body();

                if (movieResponse != null) {

                    ArrayList<Movie> movies = movieResponse.getMovies();
                    moviesLiveData.postValue(movies);
                }
            }

            @Override
            public void onFailure(Call<MovieResponse> call, Throwable t) {
                t.getMessage();
            }
        });
    }
}
public class SearchMovieViewModel extends ViewModel {

    private final MutableLiveData<List<Genre>> genresNames = new MutableLiveData<>();
    private final MutableLiveData<List<Movie>> moviesSearching = new MutableLiveData<>();

    public SearchMovieViewModel() {

        GenreAPIManager genreManager = new GenreAPIManager();
        genreManager.getGenreNames(genresNames);

        SearchAPIManager searchManager = new SearchAPIManager();
        searchManager.getMoviesWithSearching(moviesSearching, Constants.MOVIE_SEARCH);
    }

    public MutableLiveData<List<Genre>> getGenresNames() {
        return genresNames;
    }
    public MutableLiveData<List<Movie>> getMoviesWithSearching() {
        return moviesSearching;
    }

}
public class SearchMovieFragment extends Fragment {

    SearchMovieAdapter adapter;
    private EditText etSearch;
    private ImageButton ibSearch;

    private RecyclerView rvMovieSearch;

    private SearchMovieViewModel searchMovieViewModel;

    public static SearchMovieFragment newInstance() {
        return new SearchMovieFragment();
    }

    @Override
    public View onCreateView(@NonNull LayoutInflater inflater, @Nullable ViewGroup container,
                             @Nullable Bundle savedInstanceState) {
        return inflater.inflate(R.layout.search_movie_fragment, container, false);
    }

    @Override
    public void onViewCreated(@NonNull View view, @Nullable Bundle savedInstanceState) {
        super.onViewCreated(view, savedInstanceState);

        etSearch = view.findViewById(R.id.etSearch);
        ibSearch = view.findViewById(R.id.ibSearch);
        rvMovieSearch = view.findViewById(R.id.rvMovieSearch);

        rvMovieSearch.setLayoutManager(new VegaLayoutManager());

        ibSearch.setOnClickListener(v -> {

            if (etSearch.getText().toString().equals("")) {
                etSearch.setError("Type Something");
                return;
            }

            Constants.MOVIE_SEARCH = etSearch.getText().toString();

            searchMovieViewModel = new ViewModelProvider(this).get(SearchMovieViewModel.class);
            searchMovieViewModel.getMoviesWithSearching().observe(getViewLifecycleOwner(), (movies -> {
                searchMovieViewModel.getGenresNames().observe(getViewLifecycleOwner(), genres -> {

                    adapter = new SearchMovieAdapter(movies, genres);
                    rvMovieSearch.setAdapter(adapter);
                    rvMovieSearch.scheduleLayoutAnimation();

                });
            }));
        });
    }
}
1 Answers

You need to change the page number from the query so that you can get more data from the API

Here you return only page=1 for every request

public interface SearchMovieService {

    @GET("search/movie?api_key=&language=en-US&page=1&include_adult=false")
    Call<MovieResponse> getMoviesWithSearching(@Query("query") String query);
}

But you can make the page as a query parameter

public interface SearchMovieService {

    @GET("search/movie?api_key=&language=en-US&include_adult=false")
    Call<MovieResponse> getMoviesWithSearching(@Query("query") String query, 
                                              (@Query("page") long page);
}

And apply that when you request the service in activity:

long page = 1;
Call<MovieResponse> movieHTTPRequest = searchMovieService.getMoviesWithSearching(query, page);

Now you can increment the page value whenever you want to get new list of data.

UPDATE:

let's say i searched for a spiderman movie, it will show me every movie that has the keyword spiderman in it, and then when i try to search again for a different movie with a different keyword it will keep showing the results from spiderman search

The MutableLiveData didn't actually being triggered for the new query, so its data doesn't change, you need to enqueue the data again in order to make the MutableLiveData updates the underlying data that being observed.

Notice that the ViewModel constructor won't get called again whenever you make a new query, so you need to add searchManager.getMoviesWithSearching() to somewhere else.

To to that you need to add a method in the ViewModel that renew the search

public class SearchMovieViewModel extends ViewModel {

    private final MutableLiveData<List<Genre>> genresNames = new MutableLiveData<>();
    private final MutableLiveData<List<Movie>> moviesSearching = new MutableLiveData<>();

    public SearchMovieViewModel() {

        GenreAPIManager genreManager = new GenreAPIManager();
        genreManager.getGenreNames(genresNames);

        SearchAPIManager searchManager = new SearchAPIManager();
        searchManager.getMoviesWithSearching(moviesSearching, Constants.MOVIE_SEARCH);
    }

    public MutableLiveData<List<Genre>> getGenresNames() {
        return genresNames;
    }
    public MutableLiveData<List<Movie>> getMoviesWithSearching() {
        return moviesSearching;
    }

    public void updateMoviesWithSearching() {
        searchManager.getMoviesWithSearching(moviesSearching, Constants.MOVIE_SEARCH);
    }

}

And then call updateMoviesWithSearching() whenever you want to update the list. also make sure that you update Constants.MOVIE_SEARCH with the query

And whenever you make a new query: call updateMoviesWithSearching()

    ibSearch.setOnClickListener(v -> {

        if (etSearch.getText().toString().equals("")) {
            etSearch.setError("Type Something");
            return;
        }

        Constants.MOVIE_SEARCH = etSearch.getText().toString();

        searchMovieViewModel = new ViewModelProvider(this).get(SearchMovieViewModel.class);

       searchMovieViewModel.updateMoviesWithSearching();
        searchMovieViewModel.getMoviesWithSearching().observe(getViewLifecycleOwner(), (movies -> {
            searchMovieViewModel.getGenresNames().observe(getViewLifecycleOwner(), genres -> {

                adapter = new SearchMovieAdapter(movies, genres);
                rvMovieSearch.setAdapter(adapter);
                rvMovieSearch.scheduleLayoutAnimation();

            });
        }));
    });
Related