简体   繁体   English

recyclerview 在使用搜索过滤列表后打开错误的项目

[英]recyclerview opens wrong item after filtering list using search

This here is my Menu Fragment这是我的菜单片段

public class MenuFragment extends Fragment {


    @BindView(R.id.rvMenu)
    RecyclerView rvMenu;
    @BindView(R.id.etSearch)
    EditText etSearch;
    @BindView(R.id.llNoDataFound)
    LinearLayout llNoDataFound;
    @BindView(R.id.llSearch)
    LinearLayout llSearch;
    RestaurantDatabase restaurantDatabase;
    List<ItemTable> itemTableList;
    ItemListAdapter itemListAdapter;
    MySharedPreference mySharedPreference;

    @Override
    public View onCreateView(LayoutInflater inflater, ViewGroup container,
                             Bundle savedInstanceState) {
        // Inflate the layout for this fragment
        View root = inflater.inflate(R.layout.fragment_menu, container, false);
        ButterKnife.bind(this, root);
        initAll();
        return root;
    }


    private void initAll() {

        restaurantDatabase = RestaurantDatabase.getRestaurantDatabase(getContext());
        mySharedPreference = new MySharedPreference(getContext());
        itemTableList = new ArrayList<>();
        itemListAdapter = new ItemListAdapter(getContext(), itemTableList, position -> {
            ItemTable itemTable = itemTableList.get(position);
            Intent intent = new Intent(getContext(), AddMenuActivity.class);
            intent.putExtra("data", itemTable);
            intent.setFlags(Intent.FLAG_ACTIVITY_CLEAR_TASK | Intent.FLAG_ACTIVITY_CLEAR_TOP);
            startActivityForResult(intent, 100);
        });
        rvMenu.setLayoutManager(new GridLayoutManager(getContext(), 2));
        rvMenu.setItemAnimator(new DefaultItemAnimator());

        rvMenu.setAdapter(itemListAdapter);

        ItemTouchHelper itemTouchHelper = new ItemTouchHelper(simpleCallback);
        itemTouchHelper.attachToRecyclerView(rvMenu);
        getDataFromApi();

        etSearch.addTextChangedListener(new TextWatcher() {
            @Override
            public void beforeTextChanged(CharSequence charSequence, int i, int i1, int i2) {
                    /*
                    This method is called to notify you that, within s, the count characters beginning at the start are about to be replaced by new text with length after.
                    */
            }

            @Override
            public void onTextChanged(CharSequence charSequence, int i, int i1, int i2) {
                     /*
                    This method is called to notify you that, within s, the count characters beginning at the start have just replaced old text that had length before.
                    */
            }

            @Override
            public void afterTextChanged(Editable editable) {
                itemListAdapter.getFilter().filter(editable.toString());
            }
        });

    }

    ItemTable deletedItem = null;

    ItemTouchHelper.SimpleCallback simpleCallback = new ItemTouchHelper.SimpleCallback(0, ItemTouchHelper.LEFT | ItemTouchHelper.RIGHT) {
        @Override
        public boolean onMove(@NonNull RecyclerView recyclerView, @NonNull RecyclerView.ViewHolder viewHolder, @NonNull RecyclerView.ViewHolder target) {
            return false;
        }

        @Override
        public void onSwiped(@NonNull RecyclerView.ViewHolder viewHolder, int direction) {

            int position = viewHolder.getAdapterPosition();
            switch (direction) {
                case ItemTouchHelper.LEFT:
                    direction(position);
                    break;
                case ItemTouchHelper.RIGHT:
                    direction(position);
                    break;
                default:
                    break;
            }
        }

        private void direction(int position) {
            deleteDataFromLocalDatabase(position);
            deletedItem = itemTableList.get(position);
            undoMethod(deletedItem, position);
        }

        @Override
        public void onChildDraw(@NonNull Canvas c, @NonNull RecyclerView recyclerView, @NonNull RecyclerView.ViewHolder viewHolder, float dX, float dY, int actionState, boolean isCurrentlyActive) {

            new RecyclerViewSwipeDecorator.Builder(c, recyclerView, viewHolder, dX, dY, actionState, isCurrentlyActive)
                    .addBackgroundColor(ContextCompat.getColor(getContext(), R.color.gray))
                    .addActionIcon(R.drawable.ic_baseline_delete_outline_24)
                    .create()
                    .decorate();

            super.onChildDraw(c, recyclerView, viewHolder, dX, dY, actionState, isCurrentlyActive);
        }
    };

    public void undoMethod(ItemTable deletedItem, int position) {
        Snackbar.make(rvMenu, "" + deletedItem.getItemName() + " is deleted Successfully", BaseTransientBottomBar.LENGTH_LONG)
                .setAction("Undo", view -> {
                    itemTableList.add(position, deletedItem);
                    itemListAdapter.notifyItemChanged(position);
                    try {
                        Thread thread = new Thread() {
                            @Override
                            public void run() {
                                Looper.prepare();

                                /*
                                do In background
                                * */
                                ItemTable itemTable;
                                try {
                                    itemTable = new ItemTable(deletedItem.getItemName(), deletedItem.getItemImage(), deletedItem.getItemPrice(),mySharedPreference.getrdRestaurantName());
                                } catch (NumberFormatException ex) {
                                    itemTable = new ItemTable(deletedItem.getItemName(), deletedItem.getItemImage(), 0,mySharedPreference.getrdRestaurantName());
                                }

                                Long aLong = restaurantDatabase.getItemDao().insertItemTable(itemTable);

                                final Handler handler = new Handler(Looper.getMainLooper());
                                handler.postDelayed(new Runnable() {
                                    @Override
                                    public void run() {

                                        /*
                                        post background
                                        * */
                                        if (aLong > 0) {
                                            getDataFromApi();
                                        } else {
                                            Toast.makeText(getContext(), "Insert Failed", Toast.LENGTH_SHORT).show();
                                        }
                                        handler.removeCallbacks(this);


                                    }
                                }, 0000);

                                Looper.loop();
                            }
                        };
                        thread.start();

                    } catch (Exception ex) {
                        Log.e("error =>", "" + ex.getMessage());
                        ex.printStackTrace();
                    }

                }).show();
    }

    @Override
    public void onActivityResult(int requestCode, int resultCode, @Nullable Intent data) {
        super.onActivityResult(requestCode, resultCode, data);
        if (requestCode == 100 && resultCode == Activity.RESULT_OK) {
            getDataFromApi();
        }
    }

    @OnClick(R.id.fbtnAdd)
    public void onbtnAddClick() {
        Intent intent = new Intent(getContext(), AddMenuActivity.class);
        intent.setFlags(Intent.FLAG_ACTIVITY_CLEAR_TASK | Intent.FLAG_ACTIVITY_CLEAR_TOP);
        startActivityForResult(intent, 100);
        getActivity().overridePendingTransition(R.anim.slide_up,
                R.anim.slide_down);
    }

    public void getDataFromApi() {
        try {
            Thread thread = new Thread() {
                @Override
                public void run() {
                    Looper.prepare();

                    /*
                    do In background
                    * */
                    List<ItemTable> itemTables = restaurantDatabase.getItemDao().fetchAllItemTableData(mySharedPreference.getrdRestaurantName());

                    final Handler handler = new Handler(Looper.getMainLooper());
                    handler.postDelayed(() -> {

                        /*
                        post background
                        * */
                        itemTableList.clear();
                        itemTableList.addAll(itemTables);
                        if (itemTableList.isEmpty()) {
                            mySharedPreference.setMenuSwipeValue(true);
                            llNoDataFound.setVisibility(View.VISIBLE);
                            llSearch.setVisibility(View.GONE);
                        } else {
                            llNoDataFound.setVisibility(View.GONE);
                            llSearch.setVisibility(View.VISIBLE);
                        }
                        if (itemTableList.size() > 1) {
                            mySharedPreference.setMenuSwipeValue(false);
                        }
                        if (itemTableList.size() == 1 && mySharedPreference.getMenuSwipeValue()) {
                            showSwipeDialog();
                        }
                        itemListAdapter.notifyDataSetChanged();


                    }, 0000);

                    Looper.loop();
                }
            };
            thread.start();

        } catch (Exception ex) {
            Log.e("ERROR =>", "" + ex.getMessage());
            ex.printStackTrace();
        }
    }

    public void deleteDataFromLocalDatabase(int position) {
        try {
            Thread thread = new Thread() {
                @Override
                public void run() {
                    Looper.prepare();

                    /*
                    do In background
                    * */
                    int delete = restaurantDatabase.getItemDao().deleteItemTableData(itemTableList.get(position));
                    Boolean aBoolean;
                    if (delete > 0) {
                        aBoolean = true;
                    } else {
                        aBoolean = false;
                    }

                    final Handler handler = new Handler(Looper.getMainLooper());
                    handler.postDelayed(new Runnable() {
                        @Override
                        public void run() {

                            /*
                            post background
                            * */
                            if (Boolean.TRUE.equals(aBoolean)) {
                                getDataFromApi();
                            } else {
                                Toast.makeText(getContext(), "Failed Delete Item", Toast.LENGTH_SHORT).show();
                            }

                            handler.removeCallbacks(this);


                        }
                    }, 0000);

                    Looper.loop();
                }
            };
            thread.start();

        } catch (Exception ex) {
            Log.e("ERROR =>", "" + ex.getMessage());
            ex.printStackTrace();
        }
    }

    private void showSwipeDialog() {

        Dialog dialogSwipe = new Dialog(getActivity(), android.R.style.Theme_Dialog);
        dialogSwipe.getWindow().setBackgroundDrawable(new ColorDrawable(Color.TRANSPARENT));
        dialogSwipe.requestWindowFeature(Window.FEATURE_NO_TITLE);
        dialogSwipe.setContentView(R.layout.dialog_swipe_left_right);


        dialogSwipe.show();
        dialogSwipe.setCancelable(false);

        TextView tvGotIt = (TextView) dialogSwipe.findViewById(R.id.tvGotIt);

        tvGotIt.setOnClickListener(view -> {
            dialogSwipe.dismiss();
            mySharedPreference.setMenuSwipeValue(false);
        });


    }

}

And this here is my ItemListAdapter这是我的ItemListAdapter

public class ItemListAdapter extends RecyclerView.Adapter<ItemListAdapter.MyViewHolder> implements Filterable {

    List<ItemTable> itemTableList;
    List<ItemTable> filterableItemList;
    OnItemEditOrDeleteListener onItemEditOrDeleteListener;
    Context context;
    Random random;
    String[] colour;

    public interface OnItemEditOrDeleteListener {
        void onItemClicked(int position);
    }

    public ItemListAdapter(Context context, List<ItemTable> itemTableList, OnItemEditOrDeleteListener onItemEditOrDeleteListener) {
        colour = new String[]{"#F8E096", "#F8D9D7", "#FDE1E1", "#FDE4C0", "#FAD9CE", "#F6B1C9", "#E8FAD3", "#E3FBF9", "#F4DEF8", "#D9EDFD", "#D2D7F4", "#E6E5E5"};
        random = new Random();
        filterableItemList = itemTableList;
        this.context = context;
        this.onItemEditOrDeleteListener = onItemEditOrDeleteListener;
        this.itemTableList = itemTableList;
    }

    @Override
    public Filter getFilter() {
        return new Filter() {
            @Override
            protected FilterResults performFiltering(CharSequence charSequence) {
                String charsequence = charSequence.toString();
                if (charsequence.isEmpty()) {
                    filterableItemList = itemTableList;
                } else {
                    List<ItemTable> menuListModels = new ArrayList<>();
                    for (ItemTable row : itemTableList) {
                        if (row.getItemName().toLowerCase().contains(charsequence.toLowerCase())) {
                            menuListModels.add(row);
                        }
                    }
                    filterableItemList = menuListModels;
                }
                FilterResults filterResults = new FilterResults();
                filterResults.values = filterableItemList;
                return filterResults;
            }

            @Override
            protected void publishResults(CharSequence charSequence, FilterResults filterResults) {
                filterableItemList = (ArrayList<ItemTable>) filterResults.values;
                notifyDataSetChanged();
            }
        };
    }


    @NonNull
    @Override
    public MyViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) {
        View itemView = LayoutInflater.from(parent.getContext()).inflate(R.layout.menu_item_inflater, parent, false);
        return new MyViewHolder(itemView);
    }

    public class MyViewHolder extends RecyclerView.ViewHolder {

        @BindView(R.id.tvMenuName)
        TextView tvMenuName;
        @BindView(R.id.tvMenuPrice)
        TextView tvMenuPrice;
        @BindView(R.id.ivMenuImage)
        CircleImageView ivMenuImage;
        @BindView(R.id.cvMenu)
        CardView cvMenu;

        public MyViewHolder(@NonNull View itemView) {
            super(itemView);
            ButterKnife.bind(this,itemView);
        }
    }

    @Override
    public void onBindViewHolder(@NonNull MyViewHolder holder, int position) {
        ItemTable data = filterableItemList.get(holder.getAdapterPosition());

        holder.tvMenuName.setText("" + data.getItemName());
        holder.tvMenuPrice.setText("€ " + data.getItemPrice());
        if (data.getItemImage() != null) {
            Glide.with(context)
                    .load(data.getItemImage())
                    .centerCrop()
                    .into(holder.ivMenuImage);
        } else {
            Glide.with(context)
                    .load(R.drawable.background)
                    .centerCrop()
                    .into(holder.ivMenuImage);
        }

        holder.cvMenu.setOnClickListener(view -> onItemEditOrDeleteListener.onItemClicked(holder.getAdapterPosition()));

        holder.cvMenu.setCardBackgroundColor(Color.parseColor(colour[random.nextInt(colour.length - 1)]));

    }


    @Override
    public int getItemCount() {
        return filterableItemList.size();
    }
}

Basically, if I don't use the search filter the recycler works as intended, when I click an item it opens and displays the information of the item clicked.基本上,如果我使用搜索过滤器,回收器会按预期工作,当我单击一个项目时,它会打开并显示所单击项目的信息。

BUT if I filter the list using the search filter and I click an item, it will open and display wrong information.但是,如果我使用搜索过滤器过滤列表并单击一个项目,它将打开并显示错误信息。 I noticed that the information that it opens when using the search filter is that it displays the info of the position of the item that was there before using the search filter.我注意到它在使用搜索过滤器时打开的信息是它显示了在使用搜索过滤器之前存在的项目的 position 的信息。

I searched and most probably the problem is somewhere in my adapter but I can't find the problem.我进行了搜索,很可能问题出在我的适配器中,但我找不到问题。

itemListAdapter = new ItemListAdapter(getContext(), itemTableList, position -> {
    ItemTable itemTable = itemTableList.get(position); //<<<< The error is here

});

The problem is that you get the clicked item from the original list in the fragment that you initially send to the adapter.问题是您从最初发送给适配器的片段中的原始列表中获取单击的项目。

Solution:解决方案:

Get the item from the filtered list, you can create a method in the adapter that returns the filtered list:从过滤列表中获取项目,您可以在适配器中创建一个返回过滤列表的方法:

public List<ItemTable> getFilteredList() {
    return filterableItemList;
}

And replace:并替换:

ItemTable itemTable = itemTableList.get(position);

With:和:

ItemTable itemTable = itemListAdapter.getFilteredList().get(position);

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM