RecyclerView加载下一页后自动回到顶部的问题求助
解决RecyclerView加载下一页后自动回顶的问题
你的问题根源很明确:每次加载新数据时,你都重新创建了Data_Adapter实例并调用recyclerView.setAdapter(adapter),这会强制RecyclerView重新初始化整个布局,导致滚动位置被重置到顶部。下面是具体的修复方案:
核心修复思路
- 只初始化一次Adapter:在Activity的初始化阶段(比如
onCreate)就创建Adapter并绑定到RecyclerView,不要在每次加载数据时重复创建。 - 更新数据后通知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
相关产品推荐
相关产品推荐

