如何使用recyclerview:1.2.0-alpha02实现RecyclerView滚动位置自动保存与恢复
实现RecyclerView滚动位置自动保存恢复方案
第一步:升级RecyclerView依赖
直接使用最新稳定版即可,无需使用老旧的alpha测试版,在模块级build.gradle的dependencies块中添加:
implementation "androidx.recyclerview:recyclerview:1.3.2"
该版本默认启用滚动位置自动恢复能力,支持StaggeredGridLayoutManager等官方布局管理器。
第二步:核心前提条件
你需要先确认布局文件中的RecyclerView已设置唯一的android:id,View的状态保存依赖id实现,无id的控件无法自动保存状态。
第三步:修复现有代码逻辑问题
3.1 修改PostAdapter_Home.java
- 移除
mUploads的static修饰符,避免多实例数据共享异常 - 开启稳定ID,重写
getItemId方法,用每个Upload的唯一key作为item标识
修改后代码如下:
public class PostAdapter_Home extends RecyclerView.Adapter<PostAdapter_Home.PostViewHolder> { // 移除static修饰 private List<Upload> mUploads; private Context mcontext; public PostAdapter_Home(Context context, List<Upload> uploads) { mUploads = uploads; mcontext = context; // 开启稳定ID setHasStableIds(true); } // 新增重写getItemId方法 @Override public long getItemId(int position) { // 用每个Upload的唯一key生成id,保证唯一性 return mUploads.get(position).getmKey().hashCode(); } @NonNull @Override public PostViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) { View view = LayoutInflater.from(mcontext).inflate(R.layout.ex_home, parent, false); return new PostViewHolder(view); } @Override public void onBindViewHolder(@NonNull PostViewHolder holder, int position) { Shimmer shimmer = new Shimmer.ColorHighlightBuilder() .setBaseColor(Color.parseColor("#F3F3F3")) .setBaseAlpha(1) .setHighlightColor(Color.parseColor("#E7E7E7")) .setHighlightAlpha(1) .setDropoff(50) .build(); ShimmerDrawable shimmerDrawable = new ShimmerDrawable(); shimmerDrawable.setShimmer(shimmer); Upload uploadCurrent = mUploads.get(position); Glide.with(mcontext) .load(uploadCurrent.getmImageUrl()) .diskCacheStrategy(DiskCacheStrategy.AUTOMATIC) .placeholder(shimmerDrawable) .centerCrop() .fitCenter() .into(holder.imageView); } @Override public int getItemCount() { return mUploads.size(); } public static class PostViewHolder extends RecyclerView.ViewHolder { private final ShapeableImageView imageView; public PostViewHolder(@NonNull View itemView) { super(itemView); imageView = itemView.findViewById(R.id.imagePostHome); } } }
3.2 修改Home_Fragment.java
- 调整初始化顺序:先初始化数据列表、Adapter、RecyclerView配置,再加载数据
- 移除手动调用
scrollToPosition的代码,交由系统自动恢复 - 优化数据加载逻辑,避免数据更新重置滚动状态
修改后核心代码如下:
private final String KEY_RECYCLER_STATE = "recycler_state"; public List<Upload> mUploads; PostAdapter_Home postsAdapter; ShimmerFrameLayout shimmerFrameLayout; private RecyclerView postRecyclerView; private int pastVisibleItems, visibleItemCount, totalItemCount; @SuppressLint("SourceLockedOrientationActivity") @Nullable @Override public View onCreateView(@NonNull LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) { View view = inflater.inflate(R.layout.fragment_home, container, false); requireActivity().setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_PORTRAIT); MaterialToolbar materialToolbar = view.findViewById(R.id.toolbar); materialToolbar.setOnMenuItemClickListener(toolbarItemClickListener); postRecyclerView = view.findViewById(R.id.recyclerViewHome); shimmerFrameLayout = view.findViewById(R.id.shimmerEffect); StaggeredGridLayoutManager staggeredGridLayoutManager = new StaggeredGridLayoutManager(1, StaggeredGridLayoutManager.VERTICAL); postRecyclerView.setLayoutManager(staggeredGridLayoutManager); // 先初始化数据列表和Adapter mUploads = new ArrayList<>(); postsAdapter = new PostAdapter_Home(getContext(), mUploads); postRecyclerView.setAdapter(postsAdapter); // 再启动数据加载 shimmerFrameLayout.startShimmer(); getData(); return view; } private void getData() { databaseReference.addValueEventListener(new ValueEventListener() { @SuppressLint("NotifyDataSetChanged") @Override public void onDataChange(@NonNull DataSnapshot snapshot) { List<Upload> newUploads = new ArrayList<>(); if (snapshot.exists()) { for (DataSnapshot dataSnapshot : snapshot.getChildren()) { Upload upload = dataSnapshot.getValue(Upload.class); assert upload != null; upload.setmKey(dataSnapshot.getKey()); newUploads.add(upload); } } mUploads.clear(); mUploads.addAll(newUploads); postsAdapter.notifyDataSetChanged(); shimmerFrameLayout.stopShimmer(); shimmerFrameLayout.setVisibility(View.GONE); postRecyclerView.setVisibility(View.VISIBLE); } @Override public void onCancelled(@NonNull DatabaseError error) { // 处理异常逻辑 } }); }
可选优化(推荐)
如果想进一步提升性能、避免全局刷新带来的闪烁问题,可以用DiffUtil替代notifyDataSetChanged做局部更新,滚动位置恢复的稳定性会更高。
内容的提问来源于stack exchange,提问作者Vasant Raval
相关产品推荐
相关产品推荐

