英文:
Android RecyclerView prevent recycling all items
问题
我有一个RecyclerView,用户可以将项目拖放到RecyclerView中的不同位置。
到目前为止一切正常。
我的问题是当RecyclerView中的项目多于它可以显示的项目时。所以当它回收其内容时。当用户将项目拖放到不同位置,然后滚动离开这部分时,位置更改不会被保存。用户只会看到项目的旧位置。
您可以在下面的.gif中看到此问题。
我已经尝试了几种方法,例如:
recyclerViewItem.getRecycledViewPool().setMaxRecycledViews(0,0);
recyclerViewItem.setItemViewCacheSize(30);
和
holder.setIsRecyclable(false);
在我的onBindViewHolder
方法中。
但似乎没有任何方法适用于我。
是否有人知道这个问题的解决方案?
我的Fragment类:
public class ShoppinglistFragment extends Fragment {
// ...(您的其他代码)
}
和我的Adapter类:
public class ShoppinglistAdapter extends ListAdapter<Shoppinglist, ShoppinglistAdapter.NoteHolder> implements ItemMoveCallback.ItemTouchHelperContract {
// ...(您的其他代码)
}
英文:
I have a RecyclerView in which the user can drag and drop an item to a different position in the RecyclerView.
So far everything works fine.
My problem begins when the RecyclerView has more items than it can display. So when it recycle his content. When the user drag and drop an item to a different position and than scroll away from this part the position changes are not saved. The user just see the old positions for the items.
You can see this issue in the .gif below.
I already tried several things out like:
recyclerViewItem.getRecycledViewPool().setMaxRecycledViews(0,0);
recyclerViewItem.setItemViewCacheSize(30);
and
holder.setIsRecyclable(false);
inside of my onBindViewHolder.
But nothing seems to work for me.
Does anyone know a solution for this problem?
My Fragment class:
public class ShoppinglistFragment extends Fragment {
private ViewModel viewModel;
private ShoppinglistAdapter adapterShoppingItem = new ShoppinglistAdapter();
private RecyclerView recyclerViewItem;
private Boolean fragmentStarted = false;
@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
View view = inflater.inflate(R.layout.shoppinglist_layout, container, false);
recyclerViewItem = view.findViewById(R.id.recyclerViewShoppinglist);
return view;
}
@Override
public void onActivityCreated(@Nullable Bundle savedInstanceState) {
super.onActivityCreated(savedInstanceState);
viewModel = ViewModelProviders.of(getActivity()).get(ViewModel.class);
fragmentStarted = true;
recyclerViewItem.setLayoutManager(new LinearLayoutManager(getContext()));
recyclerViewItem.setHasFixedSize(false);
recyclerViewItem.getRecycledViewPool().setMaxRecycledViews(0,0);
recyclerViewItem.setItemViewCacheSize(30);
recyclerViewItem.setAdapter(adapterShoppingItem);
ItemTouchHelper.Callback callback =
new ItemMoveCallback(adapterShoppingItem);
ItemTouchHelper touchHelper = new ItemTouchHelper(callback);
touchHelper.attachToRecyclerView(recyclerViewItem);
//fetch all Shoppinglist Items from local storage
viewModel.getAllShoppinglistItems().observe((LifecycleOwner) this, new Observer <List<Shoppinglist>>() {
@Override
public void onChanged(@Nullable List<Shoppinglist> items) {
if (fragmentStarted){
adapterShoppingItem.submitList(items);
fragmentStarted = false;
}
}
});
adapterShoppingItem.setOnPositionChanged(new ShoppinglistAdapter.onPositionChanged() {
@Override
public void onPositionChanged(Shoppinglist fromItem, Shoppinglist toItem, int fromPosition, int toPosition) {
int fromPositionServer = fromItem.getPosition();
int toPositionServer = toItem.getPosition();
fromItem.setPosition(toPositionServer);
toItem.setPosition(fromPositionServer);
//updating Shoppinglist Item locally
viewModel.updateItem(fromItem);
viewModel.updateItem(toItem);
}
});
}
}}
and my Adapter class:
public class ShoppinglistAdapter extends ListAdapter<Shoppinglist, ShoppinglistAdapter.NoteHolder> implements ItemMoveCallback.ItemTouchHelperContract {
public Integer ressourceType;
private onPositionChanged onPositionChanged;
private ArrayList<Shoppinglist> globalItemList = new ArrayList<Shoppinglist>();
public ShoppinglistAdapter() {
super(DIFF_CALLBACK);
Integer valueOf = Integer.valueOf(0);
this.ressourceType = valueOf;
}
private static final DiffUtil.ItemCallback<Shoppinglist> DIFF_CALLBACK = new DiffUtil.ItemCallback<Shoppinglist>() {
@Override
public boolean areItemsTheSame(Shoppinglist oldItem, Shoppinglist newItem) {
return oldItem.getSqlid() == newItem.getSqlid();
}
@Override
public boolean areContentsTheSame(Shoppinglist oldItem, Shoppinglist newItem) {
return oldItem.getTitle().equals(newItem.getTitle());
}
};
@NonNull
@Override
public NoteHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) {
View itemView = LayoutInflater.from(parent.getContext())
.inflate(R.layout.shoppinglist_item, parent, false);
return new NoteHolder(itemView);
}
@Override
public void onBindViewHolder(@NonNull NoteHolder holder, int position) {
Shoppinglist currentItem = getItem(position);
holder.setIsRecyclable(false);
holder.tv.setText(currentItem.getTitle());
...
}
public Shoppinglist getNoteAt(int position) {
return getItem(position);
}
public class NoteHolder extends RecyclerView.ViewHolder {
private TextView tv;
public NoteHolder(View itemView) {
super(itemView);
tv= itemView.findViewById(R.id.tv);
globalItemList .add(currentNote);
}
}
public interface onPositionChanged {
void onPositionChanged(Shoppinglist fromItem, Shoppinglist toItem, int fromPosition, int toPosition);
}
public void setOnPositionChanged(ShoppinglistAdapter.onPositionChanged listener) {
this.onPositionChanged = listener;
}
@Override
public void onRowMoved(int fromPosition, int toPosition) {
//send switched Items to Fragment
onPositionChanged.onPositionChanged(globalItemList.get(fromPosition), globalItemList.get(toPosition), fromPosition, toPosition);
//switch Items inside of the global Item List
Collections.swap(globalItemList, fromPosition, toPosition);
notifyItemMoved(fromPosition, toPosition);
}
@Override
public void onRowSelected(NoteHolder myViewHolder) {}
@Override
public void onRowClear(NoteHolder myViewHolder) {}
@Override
public int getItemViewType(int position) {
return super.getItemViewType(position);
}
}
答案1
得分: 1
问题在于你应该交换ListAdapter.mDiffer
中的项,该项保存了当前显示的列表。所以,在你的代码中,globalItemList
是未使用的。请用以下内容替换你适配器中的onRowMoved
方法:
@Override
public void onRowMoved(int fromPosition, int toPosition) {
ArrayList<Shoppinglist> list = new ArrayList(getCurrentList());
Collections.swap(list, fromPosition, toPosition);
submitList(list);
}
英文:
The problem is that you should swap items in ListAdapter.mDiffer
which holds the current showing list. So, globalItemList
in your code is unused. Replace onRowMoved
of your adapter with the following one:
@Override
public void onRowMoved(int fromPosition, int toPosition) {
ArrayList<Shoppinglist> list = new ArrayList(getCurrentList());
Collections.swap(list, fromPosition, toPosition);
submitList(list);
}
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论