You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

RecyclerView加载下一页后自动回到顶部的问题求助

解决RecyclerView加载下一页后自动回顶的问题

你的问题根源很明确:每次加载新数据时,你都重新创建了Data_Adapter实例并调用recyclerView.setAdapter(adapter),这会强制RecyclerView重新初始化整个布局,导致滚动位置被重置到顶部。下面是具体的修复方案:

核心修复思路

  1. 只初始化一次Adapter:在Activity的初始化阶段(比如onCreate)就创建Adapter并绑定到RecyclerView,不要在每次加载数据时重复创建。
  2. 更新数据后通知Adapter:加载到新数据后,只需要向原数据集添加内容,然后调用Adapter的通知方法(推荐用高效的notifyItemRangeInserted而不是notifyDataSetChanged),让RecyclerView仅更新新增的item,保留原有滚动位置。

修改后的代码示例

1. 初始化Adapter(放在onCreate中)

@Override
protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.activity_main);
    
    // 初始化RecyclerView和LayoutManager
    recyclerView = findViewById(R.id.recyclerView);
    manager = new LinearLayoutManager(this); // 或者你使用的GridLayoutManager
    recyclerView.setLayoutManager(manager);
    
    // 初始化数据集和Adapter,只做一次!
    arraylist = new ArrayList<>();
    adapter = new Data_Adapter(MainActivity.this, arraylist);
    recyclerView.setAdapter(adapter);
    
    // 其他初始化代码(比如滚动监听、下拉刷新等)
    initScrollListener();
    getdata(); // 加载第一页数据
}

2. 修复滚动监听中的状态常量

你之前用了AbsListView.OnScrollListener.SCROLL_STATE_TOUCH_SCROLL,这是ListView的常量,和RecyclerView不兼容,替换为RecyclerView的官方常量:

private void initScrollListener() {
    recyclerView.addOnScrollListener(new RecyclerView.OnScrollListener() { 
        @Override 
        public void onScrollStateChanged(@NonNull RecyclerView recyclerView, int newState) { 
            super.onScrollStateChanged(recyclerView, newState); 
            // 替换为RecyclerView的拖拽状态常量
            if (newState == RecyclerView.SCROLL_STATE_DRAGGING) { 
                isScrolling = true; 
            } 
        } 
        @Override 
        public void onScrolled(@NonNull RecyclerView recyclerView, int dx, int dy) { 
            super.onScrolled(recyclerView, dx, dy); 
            currentItems = manager.getChildCount(); 
            totalItems = manager.getItemCount(); 
            scrolloutItems = manager.findFirstVisibleItemPosition(); 
            if (isScrolling && (currentItems + scrolloutItems == totalItems)) { 
                isScrolling = false; 
                getdata(pagetoken); 
                Toast.makeText(MainActivity.this, "Loading next page...", Toast.LENGTH_SHORT).show(); 
            } 
        } 
    });
}

3. 修复数据加载方法(移除重复创建Adapter的代码)

第一页加载方法:

public void getdata() {
    progress.setVisibility(View.VISIBLE);
    ApiClient.getApis().getblogdata(Constants.key).enqueue(new Callback<MyModel>() {
        @Override
        public void onResponse(Call<MyModel> call, Response<MyModel> response) {
            if (response.isSuccessful() && response.body() != null) {
                int oldItemCount = arraylist.size();
                // 添加新数据到原有数据集
                arraylist.addAll(response.body().items);
                // 通知Adapter新增了多少条数据,比notifyDataSetChanged更高效
                adapter.notifyItemRangeInserted(oldItemCount, response.body().items.size());
                
                pagetoken = response.body().nextPageToken;
            }
            swiprefresh.setRefreshing(false);
            progress.setVisibility(View.GONE);
        }
        @Override
        public void onFailure(Call<MyModel> call, Throwable t) {
            Toast.makeText(MainActivity.this, "Connection Error : \n Please Check Your Internet Connection", Toast.LENGTH_SHORT).show();
            swiprefresh.setRefreshing(false);
            progress.setVisibility(View.GONE);
        }
    });
}

下一页加载方法:

public void getdata(String pageToken) {
    ApiClient.getApis().getblogdata(Constants.key, pageToken).enqueue(new Callback<MyModel>() {
        @Override
        public void onResponse(Call<MyModel> call, Response<MyModel> response) {
            if (response.isSuccessful() && response.body() != null) {
                int oldItemCount = arraylist.size();
                arraylist.addAll(response.body().items);
                adapter.notifyItemRangeInserted(oldItemCount, response.body().items.size());
                
                if (response.body().nextPageToken != null) {
                    pagetoken = response.body().nextPageToken;
                }
                Log.d("retro", "Total items: " + arraylist.size());
            }
            swiprefresh.setRefreshing(false);
        }
        @Override
        public void onFailure(Call<MyModel> call, Throwable t) {
            Toast.makeText(MainActivity.this, "Connection Error : \n Please Check Your Internet Connection", Toast.LENGTH_SHORT).show();
            swiprefresh.setRefreshing(false);
        }
    });
}

为什么这样能解决问题?

  • 重复调用setAdapter会让RecyclerView丢弃当前的布局状态(包括滚动位置),重新绑定所有数据并从头开始布局,所以会回到顶部。
  • 仅更新数据集并调用notifyItemRangeInserted,RecyclerView会保留当前的滚动位置,只对新增的item进行布局和绑定,完全不会影响已有的内容和滚动状态。

内容的提问来源于stack exchange,提问作者Muhammad Ali

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.13 08:22:03