从 LiveData 加载后 FastAdapter 闪烁,即使数据保持不变
FastAdapter flickers after loading from LiveData even though the data stays same
我准备的问题a simple and working example at Github:
我的示例应用程序使用 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;
}
我的问题是:回收程序视图闪烁一次 - 每次下载数据时。
尽管前 30 名不会经常变化,即数据保持不变。
当我查看 Penz 先生出色的 FastAdapter 库中的示例应用程序时,我没有看到那里有任何闪烁。
更新:
我a hint知道闪烁显然是在onChanged
方法中调用mItemAdapter.clear();
引起的,我应该改用DiffUtil class。
所以我添加了一个新的 class:
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);
}
}
然后我尝试在 onChanged
方法中使用它,而不是仅仅调用 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
有几个原因,我正在寻找一种方法 "marry" 它与 DiffUtil 以消除数据时的一次性闪烁通过 HTTPS 下载并在 Room 中更新。
尝试从 getChangePayload() 方法返回一些标记对象。
@Nullable
@Override
public Object getChangePayload(final int oldItemPosition, final int newItemPosition) {
return mNewList.get(newItemPosition);
}
避免闪烁的一个简单方法是禁用 RecyclerView
的 ItemAnimator
。
mRecyclerView.setItemAnimator(null);
With the help of FastAdapter author I have been able to eliminate the one-time flickering by adding an identifier to my TopItem 显示在 RecyclerView 中:
@Override
public long getIdentifier() {
return uid;
}
并且通过在我的 TopFragment:
中使用 FastAdapterDiffUtil
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);
});
我准备的问题a simple and working example at Github:
我的示例应用程序使用 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;
}
我的问题是:回收程序视图闪烁一次 - 每次下载数据时。
尽管前 30 名不会经常变化,即数据保持不变。
当我查看 Penz 先生出色的 FastAdapter 库中的示例应用程序时,我没有看到那里有任何闪烁。
更新:
我a hint知道闪烁显然是在onChanged
方法中调用mItemAdapter.clear();
引起的,我应该改用DiffUtil class。
所以我添加了一个新的 class:
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);
}
}
然后我尝试在 onChanged
方法中使用它,而不是仅仅调用 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
有几个原因,我正在寻找一种方法 "marry" 它与 DiffUtil 以消除数据时的一次性闪烁通过 HTTPS 下载并在 Room 中更新。
尝试从 getChangePayload() 方法返回一些标记对象。
@Nullable
@Override
public Object getChangePayload(final int oldItemPosition, final int newItemPosition) {
return mNewList.get(newItemPosition);
}
避免闪烁的一个简单方法是禁用 RecyclerView
的 ItemAnimator
。
mRecyclerView.setItemAnimator(null);
With the help of FastAdapter author I have been able to eliminate the one-time flickering by adding an identifier to my TopItem 显示在 RecyclerView 中:
@Override
public long getIdentifier() {
return uid;
}
并且通过在我的 TopFragment:
中使用 FastAdapterDiffUtilmViewModel = 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);
});