java - 到达 RecyclerView 底部时从 API 接收下一页电影?
问题描述
我目前正在开展一个项目,我们必须开发一个从电影数据库 API ( https://www.themoviedb.org/ ) 检索电影的 Android 应用程序。该应用程序的功能之一是从 API 中检索热门电影并将其显示在 RecyclerView 中,如下所示:
从以下 URL 检索电影:https ://api.themoviedb.org/3/movie/popular?api_key=4c422ac80f2c83f42b8f905d4303959d&language=en&page=1
如您所见,共有 500 页。在 RecyclerView 中显示数据之前,在我的 Asynctask 中加载所有 500 个页面并不是一个解决方案,因为加载所有内容都需要很长时间。相反,我希望 RecyclerView 检测何时到达列表末尾,然后从 API 加载下一页。我不知道如何解决这个问题。
我非常接近一个解决方案,如果 RecyclerView 无法垂直滚动 2 个项目,则将 OnScrollListener 添加到 RecyclerView 并检索下一页,但我还没有正确的逻辑。使用我当前的代码,一旦我接近第一页的末尾,它将立即加载其他 499 页,这使得新加载的电影无法点击,因为任务尚未完成。我需要让它工作,以便在第二页加载后,它会再次检查 RecyclerView 是否无法垂直滚动 2 个项目。
在我的 UrlBuilder 类中构建 URL 的方法:
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();
}
}
解决方案
为什么你使用原始代码从服务器而不是改造库中获取数据?Retrofit 很容易从 server.only API 调用中获取数据,对象就是它。你可以轻松地使用库进行分页。请参阅此处如何实现它https://github.com/square/retrofit
推荐阅读
- tensorflow - 微调后如何使用语言模型进行预测?
- java - 用户模块的 Java 静态链接,无需构建 JRE 运行时映像
- amazon-web-services - Kubernetes pod 后退重新启动失败的容器并出现 CrashLoopBack 错误
- powerbi - DAX / PowerBi - 在单个标题列下列出多列的值
- scala - Scala混合具有相同包名的依赖项
- java - 如何为 JSlider 实现 EventListener。我希望当我在滑块旋钮上按住/单击鼠标左键时触发它
- react-native - React Native - CocoaPods 找不到 pod“FBReactNativeSpec”的兼容版本
- docker - Gitlab-runner,docker:20.10.2-dind 显示错误,无法在 tcp://docker:2375 连接到 Docker 守护进程
- appium-android - 我无法将 appium-server 桌面和 appium 检查器与我的智能手机连接,但我可以看到我的设备在 Windows 上的终端中连接良好
- react-native - navigation.navigate() 不适用于我的嵌套导航