В настоящее время я работаю над проектом, в котором мы должны разработать приложение Android, которое извлекает фильмы из API базы данных Mov ie (https://www.themoviedb.org/). Одной из функций приложения является получение популярных фильмов из API и отображение их в RecyclerView, например:
![enter image description here](https://i.stack.imgur.com/BYW8B.png)
Фильмы извлекаются из этого URL : https://api.themoviedb.org/3/movie/popular?api_key=4c422ac80f2c83f42b8f905d4303959d&language=en&page=1
Как видите, здесь 500 страниц. Это не решение для загрузки всех 500 страниц в моей Asynctask перед отображением данных в RecyclerView, потому что это займет слишком много времени для загрузки всего. Вместо этого я хотел бы, чтобы RecyclerView обнаружил, когда достигнут конец списка, а затем загрузил следующую страницу из API. Я понятия не имею, как это решить.
Я очень близок к решению, которое добавляет OnScrollListener в RecyclerView и извлекает следующую страницу, если RecyclerView не может прокручивать вертикально 2 элемента, но я еще не получил лог c право. С моим текущим кодом, когда я подойду ближе к концу первой страницы, он мгновенно загрузит остальные 499 страниц, что оставляет не загружаемыми только что загруженные фильмы, потому что задачи еще не завершены. Мне нужно, чтобы он работал так, чтобы после загрузки второй страницы он еще раз проверял, не может ли RecyclerView прокручивать вертикально 2 элемента.
Метод построения URL в моем классе UrlBuilder:
public static URL buildPopularMovieListUrl(int page) {
Log.d(TAG, "Method called: buildPopularMovieListUrl");
// Paths and parameters are appended to the base URL.
Uri builtUri = Uri.parse(BASE_URL_TMDB).buildUpon()
.appendPath(MOVIE_PATH)
.appendPath(POPULAR_PATH)
.appendQueryParameter(PARAM_API_KEY, API_KEY)
.appendQueryParameter(PARAM_LANGUAGE, LANGUAGE)
.appendQueryParameter(PARAM_PAGE, String.valueOf(page))
.build();
URL url = null;
try {
url = new URL(builtUri.toString());
} catch (MalformedURLException e) {
e.printStackTrace();
}
Log.d(TAG, "Built URL: " + url);
return url;
}
MainActivityFragment. java
package nl.avans.cinetopia.presentation;
import android.os.Bundle;
import android.util.Log;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import androidx.fragment.app.Fragment;
import androidx.recyclerview.widget.DividerItemDecoration;
import androidx.recyclerview.widget.LinearLayoutManager;
import androidx.recyclerview.widget.RecyclerView;
import java.util.ArrayList;
import nl.avans.cinetopia.R;
import nl.avans.cinetopia.adapters.PopularMoviesRecyclerViewAdapter;
import nl.avans.cinetopia.data_access.UrlBuilder;
import nl.avans.cinetopia.data_access.get_requests.GenresGetRequest;
import nl.avans.cinetopia.data_access.get_requests.PopularMovieGetRequest;
import nl.avans.cinetopia.data_access.utilities.JsonUtils;
import nl.avans.cinetopia.domain.Movie;
public class MainActivityFragment extends Fragment implements PopularMoviesRecyclerViewAdapter.OnItemClickListener {
private static final String TAG = MainActivityFragment.class.getSimpleName();
// RecyclerView attributes
private RecyclerView mRecyclerView;
private PopularMoviesRecyclerViewAdapter mAdapter;
private RecyclerView.LayoutManager mLayoutManager;
private ArrayList<Movie> mMovies = new ArrayList<>();
@Nullable
@Override
public View onCreateView(@NonNull LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) {
View view = inflater.inflate(R.layout.activity_main_fragment, container, false);
retrieveLatestGenresFromApi();
retrievePopularMoviesFromApi(1);
// Obtain a handle to the object.
mRecyclerView = view.findViewById(R.id.activity_main_recyclerView);
// Use a linear layout manager.
mLayoutManager = new LinearLayoutManager(getActivity());
// Connect the RecyclerView to the layout manager.
mRecyclerView.setLayoutManager(mLayoutManager);
// Specify an adapter.
mAdapter = new PopularMoviesRecyclerViewAdapter(getActivity(), mMovies);
// Connect the RecyclerView to the adapter.
mRecyclerView.setAdapter(mAdapter);
// Set OnItemClickListener.
mAdapter.setOnItemClickListener(this);
/* Add a divider to the RecyclerView. */
DividerItemDecoration dividerItemDecoration = new DividerItemDecoration(getActivity(), DividerItemDecoration.VERTICAL);
dividerItemDecoration.setDrawable(getResources().getDrawable(R.drawable.rv_divider));
mRecyclerView.addItemDecoration(dividerItemDecoration);
mRecyclerView.addOnScrollListener(new RecyclerView.OnScrollListener() {
@Override
public void onScrollStateChanged(@NonNull RecyclerView recyclerView, int newState) {
super.onScrollStateChanged(recyclerView, newState);
for (int i = 2; i < 500; i++) {
if (!recyclerView.canScrollVertically(2)) {
retrievePopularMoviesFromApi(i);
mAdapter.notifyDataSetChanged();
}
}
}
});
return view;
}
@Override
public void onViewCreated(@NonNull View view, @Nullable Bundle savedInstanceState) {
super.onViewCreated(view, savedInstanceState);
}
private void retrievePopularMoviesFromApi(int page) {
PopularMovieGetRequest task = new PopularMovieGetRequest(new PopularMovieApiListener());
task.execute(UrlBuilder.buildPopularMovieListUrl(page));
}
private void retrieveLatestGenresFromApi() {
GenresGetRequest task = new GenresGetRequest(new JsonUtils.GenresApiListener());
task.execute(UrlBuilder.buildGenreUrl());
}
/**
* Listener class for the PopularMovieGetRequest.
*/
class PopularMovieApiListener implements PopularMovieGetRequest.PopularMovieApiListener {
/**
* Fills our global ArrayList with the retrieved movies and notifies the adapter that the
* dataset has changed.
*
* @param movies The list of movies retrieved by our PopularMovieGetRequest.
*/
@Override
public void handleMovieResult(ArrayList<Movie> movies) {
Log.d(TAG, "Method called: handleMovieResult");
// Add all movies to our ArrayList and notify the adapter that the dataset has changed.
mMovies.addAll(movies);
mAdapter.notifyDataSetChanged();
}
}
@Override
public void onItemClick(int position) {
getActivity().getSupportFragmentManager().beginTransaction()
.replace(R.id.activity_main_frameLayout, new MovieDetailsActivity(mMovies.get(position).getId()))
.addToBackStack(null).commit();
}
}