Home > Software engineering >  RecyclerView onClickListener searchView showing wrong results
RecyclerView onClickListener searchView showing wrong results

Time:08-01

basically my code is about displaying user data on a recyclerView, & when clicked, would intent to an activity that displays more of that particular user's data.

onClickListener works fine if I do not use the searchView. It intents the correct data.

However, when using searchView, when first result is clicked, it always takes the data of the first item of the recyclerView that was displayed before i entered any searchView query, and so on for positions 2,3,4...

Adapter Class

public class OwnerAdapter extends RecyclerView.Adapter<OwnerAdapter.ViewHolder> {
    private final RecyclerInterface recyclerInterface;

    private ArrayList<Owners> ownerList;



    public OwnerAdapter(ArrayList<Owners> ownerList, RecyclerInterface recyclerInterface){
        this.recyclerInterface = recyclerInterface;
        this.ownerList = ownerList;
    }

    public void setFilteredList(ArrayList<Owners> filteredList) {
        this.ownerList = filteredList;
        notifyDataSetChanged();
    }

    @NonNull
    @Override
    public OwnerAdapter.ViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) {
        View view = LayoutInflater.from(parent.getContext()).inflate(R.layout.owner_recycler_row, parent, false);
        return new ViewHolder(view);

    }

    @Override
    public void onBindViewHolder(@NonNull OwnerAdapter.ViewHolder holder, int position) {
        int resource = R.drawable.ic_baseline_person_24;
        String name=ownerList.get(position).getOwner_name();
        int owner_num = ownerList.get(position).getOwner_number();
        String category = ownerList.get(position).getCategory();

        holder.setData(resource,name,owner_num,category);
    }

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

    public class ViewHolder extends RecyclerView.ViewHolder{
        private ImageView imageView;
        private TextView tvName, tvOwner_num, tvCategory;

        public ViewHolder(@NonNull View itemView) {
            super(itemView);

            imageView=itemView.findViewById(R.id.imageview1);
            tvName=itemView.findViewById(R.id.tvName);
            tvOwner_num=itemView.findViewById(R.id.tvOwner_num);
            tvCategory=itemView.findViewById(R.id.tvCategory);

            itemView.setOnClickListener(new View.OnClickListener() {
                @Override
                public void onClick(View v) {
                    if (recyclerInterface != null) {
                        int pos = getAdapterPosition();

                        if (pos != RecyclerView.NO_POSITION){
                            recyclerInterface.onRecyclerClick(pos);
                        }
                    }
                }
            });

        }

        public void setData(int resource, String name, int owner_num, String category) {

            imageView.setImageResource(resource);
            tvName.setText(name);
            tvOwner_num.setText(Integer.toString(owner_num));
            tvCategory.setText(category);



        }
    }


} 

ViewOwners Class (displays the recycler view)

public class ViewOwnerDetails extends AppCompatActivity implements RecyclerInterface {
    RecyclerView recyclerView;
    LinearLayoutManager layoutManager;
    OwnerAdapter ownerAdapter;
    ArrayList<Owners> ownerList = new ArrayList<>();
    private SearchView searchView;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.owner_recylcer_view);

        searchView = findViewById(R.id.searchView);
        searchView.clearFocus();
        searchView.setOnQueryTextListener(new SearchView.OnQueryTextListener() {
            @Override
            public boolean onQueryTextSubmit(String query) {
                return false;
            }

            @Override
            public boolean onQueryTextChange(String newText) {
                filterList(newText);
                ownerAdapter.notifyDataSetChanged();
                return true;
            }
        });

        new ViewOwnerDetails.Async().execute();


    }

    class Async extends AsyncTask<Void, Void, Void> {

        ProgressDialog pd;

        @Override
        protected void onPreExecute() { //before completing task
            //loading message
            super.onPreExecute();
            pd = new ProgressDialog(ViewOwnerDetails.this);
            pd.setMessage("Loading");
            pd.show();
        }

        @Override

        protected Void doInBackground(Void... voids) { //
            load(); //load data to userList

            return null;
        }

        @Override

        protected void onPostExecute(Void aVoid) { //after completing task

            initRecyclerView();
            pd.dismiss();
        }


    }

    public void load() {
        try {
            Class.forName("com.mysql.jdbc.Driver");

            Connection conn = DriverManager.getConnection("url", "user", "pass");
            Statement statement = conn.createStatement();
            ResultSet rs = statement.executeQuery("SELECT * FROM owner_data O INNER JOIN category C on O.catId = C.cat_id;");

            while (rs.next()) {
                String category = rs.getString("cat_name"), owner_name = rs.getString("owner_name");
                int owner_num = rs.getInt("owner_num");
                Boolean enabled = rs.getBoolean("isEnabled");
                Log.i("hi", "load: "   enabled);

                Owners owner = new Owners(owner_name, category, enabled, owner_num);
                ownerList.add(owner);
            }
        } catch (Exception e) {
            Log.i("hi", "ERROR: "   e.getMessage());

        }

    }

    private void initRecyclerView() {
        recyclerView = findViewById(R.id.recyclerView);
        layoutManager = new LinearLayoutManager(this);
        recyclerView.setLayoutManager(layoutManager);
        ownerAdapter = new OwnerAdapter(ownerList, this);
        recyclerView.setAdapter(ownerAdapter);
        ownerAdapter.notifyDataSetChanged();
    }

    public void onRecyclerClick(int position) {
        Intent intent = new Intent(ViewOwnerDetails.this, ViewFullOwnerDetails.class);

        intent.putExtra("NAME", ownerList.get(position).getOwner_name());
        intent.putExtra("OWNER_NUM", ownerList.get(position).getOwner_number());
        intent.putExtra("CATEGORY", ownerList.get(position).getCategory());
        intent.putExtra("ENABLED", ownerList.get(position).isEnabled());

        startActivity(intent);
    }

    private void filterList(String text) {
        ArrayList<Owners> filteredList = new ArrayList<>();
        for(Owners o : ownerList){
            if(o.getOwner_name().toLowerCase().contains(text.toLowerCase())){
                filteredList.add(o);
            }
            ownerAdapter.notifyDataSetChanged();
        }
        if(filteredList.isEmpty()) {
            Toast.makeText(this, "No results found", Toast.LENGTH_SHORT).show();
        } else {
            ownerAdapter.setFilteredList(filteredList);

        }
    }
}

ViewFullOwnerInfo Class (to be intented to after clicking recyclerView item)

public class ViewFullOwnerDetails extends AppCompatActivity {

    TextView tvTitle, tvName, tvOwner_num, tvCategory, tvMember;

    Button btBack, btEdit, btDeleteOwner, btView;

    ArrayList<String> associatedList = new ArrayList<>();

    @Override
    protected void onCreate(@Nullable Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.full_owner_details);

        initComponents();
        intentData();
        new asyncsetUpAssociatedList().execute();

        btBack.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                Intent intent = new Intent(ViewFullOwnerDetails.this, ViewOwnerDetails.class);
                startActivity(intent);
            }
        });

        btDeleteOwner.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                deleteConfirmationOwner();
            }
        });

        btEdit.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                Intent intent = new Intent(ViewFullOwnerDetails.this, ViewOwnerDetails.class);
                startActivity(intent);

            }
        });

        btView.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                viewDialog(associatedList);
            }
        });


    }

    public void intentData() {

        String name = getIntent().getStringExtra("NAME");
        int owner_num = getIntent().getIntExtra("OWNER_NUM", 0);
        String category = getIntent().getStringExtra("CATEGORY");
        Boolean enabled = getIntent().getBooleanExtra("ENABLED", false);


        tvTitle.setText("FULL INFORMATION");
        tvName.setText(name);
        tvOwner_num.setText(String.valueOf(owner_num));
        tvCategory.setText(category);



        if (enabled.toString() == "false") {
            tvMember.setText("Membership Disabled");
        } else if (enabled.toString() == "true") {
            tvMember.setText("Membership Enabled");
        }


    }

    private void initComponents() {
        tvTitle = (TextView) findViewById(R.id.tvTitle);
        tvName = (TextView) findViewById(R.id.tvName);
        tvOwner_num = (TextView) findViewById(R.id.tvCategory);
        tvCategory = (TextView) findViewById(R.id.tvOwner_num);
        tvMember = (TextView) findViewById(R.id.tvMember);

        btBack = (Button) findViewById(R.id.btBack);
        btDeleteOwner = (Button) findViewById(R.id.buttonDeleteOwner);
        btEdit = (Button) findViewById(R.id.btResolve);
        btView = (Button) findViewById(R.id.btViewVehicles);
    }

    private void viewDialog(List<String> associatedList) {
        String output = "";
        if (associatedList.isEmpty()) {
            output = "List empty";
        } else {
            for (int i = 0; i < associatedList.size(); i  ) {
                String vehicle = associatedList.get(i);
                output  = vehicle   "\n";
            }
        }
        AlertDialog.Builder builder = new AlertDialog.Builder(this);

        builder.setMessage("ASSOCIATED VEHICLES: \n"   output)
                .setPositiveButton("Close", new DialogInterface.OnClickListener() {
                    @Override
                    public void onClick(DialogInterface dialog, int which) {
                        dialog.cancel();
                    }
                });
        AlertDialog alertDialog = builder.create();
        alertDialog.show();
    }

    private void deleteConfirmationOwner() {
        AlertDialog.Builder builder = new AlertDialog.Builder(this);

        builder.setMessage("Are you sure you want to delete this Owner? It will delete all related vehicles also")
                .setPositiveButton("Yes", new DialogInterface.OnClickListener() {
                    @Override
                    public void onClick(DialogInterface dialog, int which) {
                        new ViewFullOwnerDetails.asyncDeleteOwner().execute();
                        Intent intent = new Intent(ViewFullOwnerDetails.this, ViewOwnerDetails.class);
                        startActivity(intent);
                        Toast.makeText(ViewFullOwnerDetails.this, "Delete Succesful!", Toast.LENGTH_LONG).show();
                    }
                })

                .setNegativeButton("No", new DialogInterface.OnClickListener() {
                    @Override
                    public void onClick(DialogInterface dialog, int which) {

                        dialog.cancel();
                    }
                });
        AlertDialog alertDialog = builder.create();
        alertDialog.show();
    }

    class asyncDeleteOwner extends AsyncTask<Void, Void, Void> {
        protected Void doInBackground(Void... voids) {
            try {
                Class.forName("com.mysql.jdbc.Driver");

                Connection conn = DriverManager.getConnection("url", "user", "pass");
                String query = String.format("DELETE FROM owner_data WHERE owner_num = '%d'", Integer.parseInt(tvOwner_num.getText().toString()));
                PreparedStatement statement = conn.prepareStatement(query);
                statement.executeUpdate();


            } catch (Exception e) {


            }
            return null;
        }

    }

    class asyncsetUpAssociatedList extends AsyncTask<Void, Void, Void> {
        @Override
        protected Void doInBackground(Void... voids) {
            try {
                Class.forName("com.mysql.jdbc.Driver");

                Connection conn = DriverManager.getConnection("url", "pass", "user");
                Statement statement = conn.createStatement();
                //String query = String.format("SELECT * FROM vehicle_data V INNER JOIN owner_data O on O.owner_num = V.owner_num WHERE V.owner_num = '%d'", Integer.parseInt(tvOwner_num.getText().toString()));
                ResultSet rs = statement.executeQuery("SELECT * FROM owner_data O INNER JOIN category C on O.catId = C.cat_id;");

                while (rs.next()) {
                    String reg_num = rs.getString("reg_num");
                    associatedList.add(reg_num);
                }
            } catch (Exception e) {
                Log.i("v", "Error: "   e.getMessage());
            }
            return null;
        }
    }
}

CodePudding user response:

when using searchView, when first result is clicked, it always takes the data of the first item of the recyclerView that was displayed before i entered any searchView query, and so on for positions 2,3,4...

This means that your recyclerView list is not getting updated properly when you search for an item. The list you are showing in the search view is different than the list that you are making changes to upon clicking.

  public void onRecyclerClick(int position) {
        Intent intent = new Intent(ViewOwnerDetails.this, ViewFullOwnerDetails.class);

        intent.putExtra("NAME", ownerList.get(position).getOwner_name());
        intent.putExtra("OWNER_NUM", ownerList.get(position).getOwner_number());
        intent.putExtra("CATEGORY", ownerList.get(position).getCategory());
        intent.putExtra("ENABLED", ownerList.get(position).isEnabled());

        startActivity(intent);
    }

So, the problem here is you are accessing the first item of your ownerList which is not the same as the filtered list. So, in order to get the correct item, you should access the filtered list rather than ownerList. You can initialise the filteredList for the whole activity and then you can use recyclerView on click accordingly. If the search view is empty, you can access items from ownerList and if it is not, you can access items from filtered list.

CodePudding user response:

In Your OwnerAdapter You should move out the logic out of the ViewHolder constructor. The data binding along with logic implementation should happen in the onBindViewHolder method:

@Override
public void onBindViewHolder(@NonNull OwnerAdapter.ViewHolder holder, int position) {

    ...

    holder.itemView.setOnCLickListener(view ->
        recyclerInterface.onRecyclerClick(position);
    );
}

The ViewHolder constructor is only used by onCreateViewHolder to initialize the ViewHolder and Views associated with it. The onBindViewHolder associates the ViewHolder with actual data. And among this data there is a new position of the ViewHolder in the adapter which provides a way to access the actual item from the list.

  • Related