Получить следующую страницу фильмов из API, когда достигнет нижней части RecyclerView? - PullRequest
0 голосов
/ 30 марта 2020

В настоящее время я работаю над проектом, в котором мы должны разработать приложение Android, которое извлекает фильмы из API базы данных Mov ie (https://www.themoviedb.org/). Одной из функций приложения является получение популярных фильмов из API и отображение их в RecyclerView, например:

enter image description here

Фильмы извлекаются из этого 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();
    }
}

1 Ответ

0 голосов
/ 30 марта 2020

Почему вы используете сырой код для извлечения данных с сервера вместо библиотеки Retrofit? Модифицировать очень просто для извлечения данных из API-интерфейса server.only с помощью объекта. Это можно легко выполнить с помощью библиотеки. Смотрите здесь, как это реализовать https://github.com/square/retrofit

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...