代码之家  ›  专栏  ›  技术社区  ›  Alexander Farber

FastAdapter在从LiveData加载后闪烁,即使数据保持不变

  •  1
  • Alexander Farber  · 技术社区  · 7 年前

    对于我准备的问题 a simple and working example at Github :

    app screenshot

    我的示例应用程序使用okhttp下载一个包含游戏中前30名玩家的JSON数组,并将它们存储到SQLite Room中。在 fragment LiveData<List<TopEntity>> 对象并更新FastAdapter实例:

    public class TopFragment extends Fragment {
        private final ItemAdapter<TopItem> mItemAdapter = new ItemAdapter<>();
        private final FastAdapter<TopItem> mFastAdapter = FastAdapter.with(mItemAdapter);
    
        private TopViewModel mViewModel;
        private ProgressBar mProgressBar;
        private RecyclerView mRecyclerView;
    
        @Override
        public View onCreateView(@NonNull LayoutInflater inflater,
                                 ViewGroup container,
                                 Bundle savedInstanceState) {
    
            mViewModel = ViewModelProviders.of(this).get(TopViewModel.class);
            mViewModel.getTops().observe(this, tops -> {
                mItemAdapter.clear();
                for (TopEntity top: tops) {
                    TopItem item = new TopItem(top);
                    mItemAdapter.add(item);
                }
            });
    
            View v = inflater.inflate(R.layout.top_fragment, container, false);
            mProgressBar = v.findViewById(R.id.progressBar);
            mRecyclerView = v.findViewById(R.id.recyclerView);
            mRecyclerView.setLayoutManager(new LinearLayoutManager(getActivity()));
            mRecyclerView.setAdapter(mFastAdapter);
    
            fetchJsonData();
    
            return v;
        }
    

    我的问题是:每次下载数据时,recycler视图都会闪烁一次。

    当我在优秀的 FastAdapter 彭兹先生的图书馆,我看不到任何闪烁。

    更新:

    我有 a hint 闪烁显然是由呼叫引起的 mItemAdapter.clear(); onChanged 方法,我应该改用DiffUtil类。

    所以我添加了一个新类:

    public class DiffCallback extends DiffUtil.Callback {
        private final List<TopItem> mOldList;
        private final List<TopItem> mNewList;
    
        public DiffCallback(List<TopItem> oldStudentList, List<TopItem> newStudentList) {
            this.mOldList = oldStudentList;
            this.mNewList = newStudentList;
        }
    
        @Override
        public int getOldListSize() {
            return mOldList.size();
        }
    
        @Override
        public int getNewListSize() {
            return mNewList.size();
        }
    
        @Override
        public boolean areItemsTheSame(int oldItemPosition, int newItemPosition) {
            TopItem oldItem = mOldList.get(oldItemPosition);
            TopItem newItem = mNewList.get(newItemPosition);
    
            return oldItem.uid == newItem.uid;
        }
    
        @Override
        public boolean areContentsTheSame(int oldItemPosition, int newItemPosition) {
            TopItem oldItem = mOldList.get(oldItemPosition);
            TopItem newItem = mNewList.get(newItemPosition);
    
            return oldItem.elo == newItem.elo &&
                    oldItem.given.equals(newItem.given) &&
                    //oldItem.photo != null && oldItem.photo.equals(newItem.photo) &&
                    oldItem.avg_time != null && oldItem.avg_time.equals(newItem.avg_time) &&
                    oldItem.avg_score == newItem.avg_score;
        }
    
        @Nullable
        @Override
        public Object getChangePayload(int oldItemPosition, int newItemPosition) {
            return super.getChangePayload(oldItemPosition, newItemPosition);
        }
    }
    

    然后我试着把它用在 一旦改变 方法而不是只调用 mItemAdapter.clear() 但是RecyclerView仍然是空的,即使 tops 具有以下元素:

    mViewModel = ViewModelProviders.of(this).get(TopViewModel.class);
    mViewModel.getTops().observe(this, tops -> {
        List<TopItem> oldList = mItemAdapter.getAdapterItems();
        List<TopItem> newList = new ArrayList<>();
        for (TopEntity top: tops) {
            TopItem item = new TopItem(top);
            newList.add(item);
        }
    
        DiffCallback diffCallback = new DiffCallback(oldList, newList);
        DiffUtil.DiffResult diffResult = DiffUtil.calculateDiff(diffCallback);
    
        mItemAdapter.getAdapterItems().clear();
        mItemAdapter.getAdapterItems().addAll(newList);
        diffResult.dispatchUpdatesTo(mFastAdapter);
    });
    

    我真正的应用程序使用 FastAdapter 出于几个原因,我正在寻找一种方法来“结婚”与它 DiffUtil 为了消除通过HTTPS下载数据并在室内更新时的一次性闪烁。

    3 回复  |  直到 7 年前
        1
  •  5
  •   aminography    7 年前

    避免闪烁的一个简单方法是禁用 RecyclerView ItemAnimator .

    mRecyclerView.setItemAnimator(null);
    
        2
  •  3
  •   Alexander Farber    7 年前

    With the help of FastAdapter author 我已经能够通过添加一个标识符来消除一次性闪烁 TopItem 在RecyclerView中显示:

    @Override
    public long getIdentifier() {
        return uid;
    }
    

    在我的系统中使用FastAdapterDiffUtil TopFragment :

    mViewModel = ViewModelProviders.of(this).get(TopViewModel.class);
    mViewModel.getTops().observe(this, tops -> {
        List<TopItem> newList = new ArrayList<>();
        for (TopEntity top: tops) {
            TopItem item = new TopItem(top);
            newList.add(item);
        }
    
        DiffUtil.DiffResult diffResult = FastAdapterDiffUtil.calculateDiff(mItemAdapter, newList);
        FastAdapterDiffUtil.set(mItemAdapter, diffResult);
    });
    
        3
  •  1
  •   UserX    7 年前

    @Nullable
    @Override
    public Object getChangePayload(final int oldItemPosition, final int newItemPosition) {
        return mNewList.get(newItemPosition);
    }
    
    推荐文章