Fragment切换时因Recycler Adapter加载出现延迟,如何优化?
优化Fragment过渡流畅度的方案
1. 延迟RecyclerView初始化,避开动画执行阶段
Fragment过渡动画运行时,UI线程若被RecyclerView初始化、布局计算占用,会直接导致卡顿。可以监听Fragment进入动画完成事件,等动画结束后再绑定Adapter:
@Override public void onViewCreated(@NonNull View view, @Nullable Bundle savedInstanceState) { super.onViewCreated(view, savedInstanceState); viewModel = new ViewModelProvider(this).get(MainViewModel.class); recyclerView.setLayoutManager(new LinearLayoutManager(requireContext())); recyclerView.setHasFixedSize(true); // 固定列表大小,减少重复布局测量 // 等待Fragment进入动画完成后再初始化Adapter getView().postOnAnimation(() -> { adapter = new BackpackAdapter(viewModel.getListItems()); recyclerView.setAdapter(adapter); }); }
2. 异步准备列表数据,避免UI线程阻塞
如果viewModel.getListItems()是同步执行的耗时操作(比如本地数据库读取、数据解析),会直接阻塞UI线程。改成在ViewModel中异步加载数据,通过LiveData通知Fragment更新:
ViewModel代码:
private MutableLiveData<List<Item>> itemListLiveData = new MutableLiveData<>(); public MainViewModel() { // 用IO线程执行耗时数据加载 Executors.newSingleThreadExecutor().execute(() -> { List<Item> items = loadItemsFromLocal(); // 耗时操作,比如读数据库 itemListLiveData.postValue(items); }); } public LiveData<List<Item>> getItemListLiveData() { return itemListLiveData; }
Fragment代码:
@Override public void onViewCreated(@NonNull View view, @Nullable Bundle savedInstanceState) { super.onViewCreated(view, savedInstanceState); viewModel = new ViewModelProvider(this).get(MainViewModel.class); recyclerView.setLayoutManager(new LinearLayoutManager(requireContext())); recyclerView.setHasFixedSize(true); adapter = new BackpackAdapter(new ArrayList<>()); // 先绑定空列表 recyclerView.setAdapter(adapter); // 观察数据变化,异步更新Adapter viewModel.getItemListLiveData().observe(getViewLifecycleOwner(), items -> { adapter.updateItems(items); }); }
Adapter新增更新方法:
public void updateItems(List<Item> newItems) { // 用DiffUtil优化列表更新,减少不必要的视图刷新 DiffUtil.DiffResult result = DiffUtil.calculateDiff(new ItemDiffCallback(this.list, newItems)); this.list.clear(); this.list.addAll(newItems); result.dispatchUpdatesTo(this); } // DiffCallback实现 private static class ItemDiffCallback extends DiffUtil.Callback { private final List<Item> oldList; private final List<Item> newList; public ItemDiffCallback(List<Item> oldList, List<Item> newList) { this.oldList = oldList; this.newList = newList; } @Override public int getOldListSize() { return oldList.size(); } @Override public int getNewListSize() { return newList.size(); } @Override public boolean areItemsTheSame(int oldItemPosition, int newItemPosition) { return oldList.get(oldItemPosition).getId() == newList.get(newItemPosition).getId(); } @Override public boolean areContentsTheSame(int oldItemPosition, int newItemPosition) { return oldList.get(oldItemPosition).equals(newList.get(newItemPosition)); } }
3. 优化RecyclerView的ViewHolder创建效率
- 用ViewBinding替代
findViewById,减少视图查找耗时:
@NonNull @Override public ViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) { ItemBinding binding = ItemBinding.inflate(LayoutInflater.from(parent.getContext()), parent, false); return new ViewHolder(binding); } class ViewHolder extends RecyclerView.ViewHolder { private final ItemBinding binding; ViewHolder(ItemBinding binding) { super(binding.getRoot()); this.binding = binding; } }
- 增加View缓存数量,减少ViewHolder重复创建:
recyclerView.setItemViewCacheSize(10); // 根据列表项数量调整缓存大小
4. 提前预加载Glide图片
首次加载时的图片解码可能占用CPU资源,可在数据准备完成后提前预加载:
// 在Fragment中数据回调后执行预加载 viewModel.getItemListLiveData().observe(getViewLifecycleOwner(), items -> { for (Item item : items) { Glide.with(requireContext()) .load(item.getImage()) .preload(); } adapter.updateItems(items); });
内容的提问来源于stack exchange,提问作者WHOATEMYNOODLES
相关产品推荐
相关产品推荐

