Search code examples
javaandroidlistviewfilteradapter

Adding an item breaks getFilter() method


Problem: Adding a list item prevents filter method from working. Otherwise the filter works correctly.

Expected: That the items and database are correctly updated from the both add item and filter methods.

Tested:

  1. Filter on current list works and applies the layout.
  2. Filter on filtered list works and applies the layout.
  3. Filter with no constraint loads the full list and applies the layout.
  4. Adding item before filter works and applies the layout.
  5. Adding item after filter works and applies the layout.
  6. Filter after adding item fails to filter results and applies no changes to the layout. No run time errors are provided.

Probable Solution: I thought I was missing an assignment to the items list to grab the updated version of the list. After checking it seems that both add item and filter methods are grabbing the updated list. I am starting to think I don't understand how the filter method works and that I am missing a method or line that the filter needs to refresh. Would appreciate suggestions on how to find what I am missing.

private void addProjectItem() {
        AlertDialog.Builder builder = new AlertDialog.Builder(this);
        View view = getLayoutInflater().inflate(R.layout.project_add_layout, null);

        final EditText title = view.findViewById(R.id.addProjectTitle);
        final EditText description = view.findViewById(R.id.addProjectDescription);

        builder.setNegativeButton(
                android.R.string.cancel,
                (dialog, which) -> dialog.cancel()
        );

        builder.setPositiveButton(
                android.R.string.ok,
                (dialog, which) -> {
                    if (!title.getText().toString().isEmpty() && !description.getText().toString().isEmpty()) {
                        ProjectItem item = new ProjectItem(
                                title.getText().toString(),
                                description.getText().toString(),
                                appDataManager.getUid(),
                                false
                        );

                        projectListManager.addItem(item);
                        adapter.updateItems(projectListManager.getList());
                    } else {
                        Toast.makeText(SecondActivity.this, projectAddError, Toast.LENGTH_SHORT).show();
                    }
                }
        );

        builder.setView(view);
        builder.show();
    }

    private class ProjectItemAdapter extends ArrayAdapter<ProjectItem> implements Filterable {
        private Context context;
        private List<ProjectItem> items;

        private ImageButton projectCompleteButton;
        private ImageButton projectDescriptionButton;
        private TextView itemTitle;
        private ImageButton projectJoinButton;

        private ProjectItemAdapter( Context context, List<ProjectItem> items) {
            super(context, -1, items);

            this.context = context;
            this.items = items;
        }

        @NonNull
        @Override
        public Filter getFilter() {
            return projectFilter;
        }

        private final Filter projectFilter = new Filter() {

            @Override
            protected FilterResults performFiltering(CharSequence constraint) {
                FilterResults results = new FilterResults();

                List<ProjectItem> found = new ArrayList<>();

                if(constraint == null || constraint.length() == 0) {
                    found.addAll(projectListManager.getList());
                } else {
                    String filterPattern = constraint.toString().toLowerCase().trim();

                    for(ProjectItem item : items){
                        if(item.getTitle().toLowerCase().contains(filterPattern)) {
                            found.add(item);
                        }
                    }
                }

                results.values = found;
                results.count = found.size();
                return results;
            }

            @Override
            protected void publishResults(CharSequence constraint, FilterResults results) {
                clear();
                addAll((List)results.values);
                notifyDataSetChanged();
            }
        };

        public void updateItems(List<ProjectItem> items) {
            this.items = items;
            notifyDataSetChanged();
        }
        
        @Override
        public int getCount() {
            return items.size();
        }

        @NonNull
        @Override
        public View getView(int position, View convertView, @NonNull ViewGroup parent) {
            // Removed as there is nothing that manipulates the list item.
            return convertView;
        }
    }
}

Solution

  • Problem was with the publish results not referencing the items list and properly casting results as a collections.

    Solution:

    @Override
    protected void publishResults(CharSequence constraint, FilterResults results) {
        items.clear();
    
        items.addAll((Collection<? extends ProjectItem>) results.values);
    
        notifyDataSetChanged();
    }