recyclerView.addOnScrollListener - "retrofit pagination with MVVM" 正在加载相同的 response/list

recyclerView.addOnScrollListener - "retrofit pagination with MVVM" is loading the same response/list

我在我的应用程序中使用 blogger API、retrofit 和 MVVM,我试图在用户滚动时使用分页来加载更多帖子,这里发生的问题是响应正在自行加载“相同列表/相同的十个帖子再次加载

这是我的代码

PostsClient Class

public class PostsClient {

    private static final String TAG = "PostsClient";

    private static final String KEY = "XYZ sensitive key!";
    private static final String BASE_URL = "https://www.googleapis.com/blogger/v3/blogs/4294497614198718393/";

    private PostInterface postInterface;
    private static PostsClient INSTANCE;

    public PostsClient() {

        Retrofit retrofit = new Retrofit.Builder()
                .baseUrl(BASE_URL)
                .addConverterFactory(GsonConverterFactory.create())
                .build();

        postInterface = retrofit.create(PostInterface.class);

    }

    public static PostsClient getINSTANCE() {
        if(INSTANCE == null){
            INSTANCE = new PostsClient();
        }
        return INSTANCE;
    }



    public Call<PostList> getPostList(){

        return postInterface.getPostList(KEY);
    }



}

[PostViewModel]

public class PostViewModel extends ViewModel {

    public static final String TAG = "PostViewModel";


    public MutableLiveData<PostList> postListMutableLiveData = new MutableLiveData<>();
    public MutableLiveData<PostList> postListByLabelMutableLiveData = new MutableLiveData<>();
    public MutableLiveData<String> finalURL = new MutableLiveData<>();
    public MutableLiveData<String> token = new MutableLiveData<>();

    public void getPosts(){


        if (token.getValue() != "") {
            finalURL.setValue(finalURL.getValue() + "&pageToken=" + token.getValue());
        }
        if (token == null) {
            return;
        }

        PostsClient.getINSTANCE().getPostList().enqueue(new Callback<PostList>() {
            @Override
            public void onResponse(@NotNull Call<PostList> call, @NotNull Response<PostList> response) {

                PostList list = response.body();

                if (list.getItems() != null) {
                    token.setValue(list.getNextPageToken());
                    postListMutableLiveData.setValue(list);
                }

                Log.i(TAG,response.body().getItems().toString());
            }

            @Override
            public void onFailure(Call<PostList> call, Throwable t) {
                Log.e(TAG,t.getMessage());
            }
        });

    }


    public void getPostListByLabel(){

        PostsByLabelClient.getINSTANCE().getPostListByLabel(finalURL.getValue()).enqueue(new Callback<PostList>() {
            @Override
            public void onResponse(Call<PostList> call, Response<PostList> response) {
                postListByLabelMutableLiveData.setValue(response.body());
            }

            @Override
            public void onFailure(Call<PostList> call, Throwable t) {

            }
        });
    }
}

HomeFragmentClass“主页”

public class HomeFragment extends Fragment {

    private PostViewModel postViewModel;
    public static final String TAG = "HomeFragment";
    private RecyclerView recyclerView;
    private PostAdapter postAdapter;
    private List<Item> itemArrayList;
    private boolean isScrolling = false;
    private int currentItems, totalItems, scrollOutItems, selectedIndex;

    public View onCreateView(@NonNull LayoutInflater inflater,
                             ViewGroup container, Bundle savedInstanceState) {

        postViewModel = new ViewModelProvider(this).get(PostViewModel.class);
        postViewModel.getPosts();

        View root = inflater.inflate(R.layout.fragment_home, container, false);

        itemArrayList = new ArrayList<>();

        recyclerView = root.findViewById(R.id.homeRecyclerView);
        postAdapter = new PostAdapter(getContext(),itemArrayList);

        LinearLayoutManager linearLayoutManager = new LinearLayoutManager(getContext());
        linearLayoutManager.setOrientation(LinearLayoutManager.VERTICAL);
        recyclerView.setLayoutManager(linearLayoutManager);
        DividerItemDecoration dividerItemDecoration = new DividerItemDecoration(recyclerView.getContext()
                , linearLayoutManager.getOrientation());
        recyclerView.setLayoutManager(linearLayoutManager);
        recyclerView.addItemDecoration(dividerItemDecoration);
        recyclerView.setAdapter(postAdapter);

//                textView.setText(s);
                postViewModel.postListMutableLiveData.observe(HomeFragment.this, new Observer<PostList>() {
                    @Override
                    public void onChanged(PostList postList) {
                        itemArrayList.addAll(postList.getItems());
                        postAdapter.notifyDataSetChanged();
                    }
                });


        recyclerView.addOnScrollListener(new RecyclerView.OnScrollListener() {
            @Override
            public void onScrollStateChanged(@NonNull RecyclerView recyclerView, int newState) {
                super.onScrollStateChanged(recyclerView, newState);
                    isScrolling = true;



            }

            @Override
            public void onScrolled(@NonNull RecyclerView recyclerView, int dx, int dy) {
                super.onScrolled(recyclerView, dx, dy);
                if (dy > 0) {
                    currentItems = linearLayoutManager.getChildCount();
                    totalItems = linearLayoutManager.getItemCount();
                    scrollOutItems = linearLayoutManager.findFirstVisibleItemPosition();
                    if (isScrolling && (currentItems + scrollOutItems == totalItems)) {
                        isScrolling = false;
                        postViewModel.getPosts();
                        postAdapter.notifyDataSetChanged();


                    }
                }

            }
        });


        return root;

    }
}

'更多解释

在 PostViewModel 上 我创建了一个变量

public MutableLiveData<String> token = new MutableLiveData<>();

这个代表新 page/response 的令牌将带有“每个页面都有一个列表/十个新帖子”

在 HomeFragment 上

我创建了三个整数值

private int currentItems, totalItems, scrollOutItems, selectedIndex;

和一个布尔值

private boolean isScrolling = false;

然后我用了recyclerView.addOnScrollListener

用这种方式加载接下来的十个帖子,但它不像我之前说的那样工作,加载相同 result/list

The result on imgur.com

每次您想获取新帖子时,您都会更改 finalURL 值:

if (token.getValue() != "") {
    finalURL.setValue(finalURL.getValue() + "&pageToken=" + token.getValue());
}

这里你使用 finalURL.getValue(),它已经包含旧的令牌值(上一页的)。第一页就可以了。

当您返回下一页时,您将获得 finalURL 的值并将新标记连接到它,尽管当前 finalURL 已经包含最后一个标记的值。所以现在 finalURL 包含几个标记,我认为 API 可以采用第一个标记,即上一页的标记(因此,您将获得相同的帖子列表)。

因此您需要将其更改为 baseURL 的常量值:

final String baseURL = "" // add base URL which is basically the initial value of the `finalURL`
if (token.getValue() != "") {
    finalURL.setValue(baseURL + "&pageToken=" + token.getValue());
}

旁注:

如果您打算将字符串与 token.getValue() != "" 进行比较,则需要将其更改为字符串 .equals() 或使用 isEmpty() 方法检查空字符串。

考虑使用新的分页库。这里有一个sample and the documentation。它的性能更好,您不必手动跟踪滚动的位置。通过遵循示例,我发现实现它相当容易,尽管它有很多样板代码。## Heading ##

经过数百次尝试,终于解决了,这里是问题的解决方案

首先 我更改了 API PostInterface 中的 GET 方法并使其采用 @URL 而不是 @Query KEY 像这样

public interface PostInterface {

    @GET
    Call<PostList> getPostList(@Url String URL);
}

Secondary 我编辑了 PostsClientBASE_URL private static String BASE_URL 中删除的 final 并创建了 setter & getter 对于 BASE URL & KEY

public static String getKEY() {
        return KEY;
    }

    public static String getBaseUrl() {
        return BASE_URL;
    }

第三次也是最后一次 我在响应后为令牌检查程序移动了这个 if 语句

public void getPosts(){

        Log.e(TAG,finalURL.getValue());

        PostsClient.getINSTANCE().getPostList(finalURL.getValue()).enqueue(new Callback<PostList>() {
            @Override
            public void onResponse(@NotNull Call<PostList> call, @NotNull Response<PostList> response) {

                PostList list = response.body();


                if (list.getItems() != null) {

                    Log.e(TAG,list.getNextPageToken());
                    token.setValue(list.getNextPageToken());
                    postListMutableLiveData.setValue(list);

                }
                if (token.getValue() == null || !token.getValue().equals("") ) {
                    finalURL.setValue(finalURL.getValue() + "&pageToken=" + token.getValue());
                }


//                Log.i(TAG,response.body().getItems().toString());
            }

            @Override
            public void onFailure(Call<PostList> call, Throwable t) {
                Log.e(TAG,t.getMessage());
            }
        });

    }