Android RecyclerView防止回收所有项目

huangapple go评论89阅读模式
英文:

Android RecyclerView prevent recycling all items

问题

我有一个RecyclerView,用户可以将项目拖放到RecyclerView中的不同位置。

到目前为止一切正常。

我的问题是当RecyclerView中的项目多于它可以显示的项目时。所以当它回收其内容时。当用户将项目拖放到不同位置,然后滚动离开这部分时,位置更改不会被保存。用户只会看到项目的旧位置。

您可以在下面的.gif中看到此问题。

Android RecyclerView防止回收所有项目

我已经尝试了几种方法,例如:

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.

Android RecyclerView防止回收所有项目

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 &lt;List&lt;Shoppinglist&gt;&gt;() {
        @Override
        public void onChanged(@Nullable List&lt;Shoppinglist&gt; 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&lt;Shoppinglist, ShoppinglistAdapter.NoteHolder&gt; implements ItemMoveCallback.ItemTouchHelperContract {

public Integer ressourceType;
private onPositionChanged onPositionChanged;
private ArrayList&lt;Shoppinglist&gt; globalItemList = new ArrayList&lt;Shoppinglist&gt;();

public ShoppinglistAdapter() {
    super(DIFF_CALLBACK);
    Integer valueOf = Integer.valueOf(0);
    this.ressourceType = valueOf;
}

private static final DiffUtil.ItemCallback&lt;Shoppinglist&gt; DIFF_CALLBACK = new DiffUtil.ItemCallback&lt;Shoppinglist&gt;() {
    @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&lt;Shoppinglist&gt; list = new ArrayList(getCurrentList());
    Collections.swap(list, fromPosition, toPosition);
    submitList(list);
}

huangapple
  • 本文由 发表于 2020年7月21日 19:13:51
  • 转载请务必保留本文链接:https://go.coder-hub.com/63013265.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定