简体   繁体   中英

SearchView stops filtering after LongClick action

In my app, I have a SearchView in the Toolbar .

When the user clicks the search icon, the SearchView expands and the user starts typing. The search query filters a RecyclerView list by title. This all works fine.

However, the filter function stops working when I perform an OnLongClick action on one of the RecyclerView items.

I have both an OnClickListener and OnLongClickListener attached to each RecyclerView holder, but it's only the OnLongClick action that stops the SearchView from filtering. I don't understand why. I've tried reinstantiating the SearchView and resetting the RecyclerView to no avail.

Here's my code:

Functions that don't affect the SearchView have been removed for the sake of space.

MainActivity.java

public class MainActivity extends AppCompatActivity {

    //LONG CLICK ACTION MODE VARIABLES
    boolean isInActionMode = false;
    TextView selectedCounterText;

    //SEARCH BAR
    SearchView searchView;

    //INSERT DIALOG TEXTVIEWS
    EditText editTitle, editCategory, editSignifier, editDate, editRecurs, editDetails;
    Button btnCreate, btnCancel;

    RecyclerView recyclerView;
    RecyclerView.LayoutManager layoutManager;
    CardAdapter adapter;
    Toolbar toolbar;

    ArrayList<Bullet> bullets = new ArrayList<>();
    ArrayList<Bullet> selectedBullets = new ArrayList<>();
    int counter = 0;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        this.setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_PORTRAIT);

        //SET DEFAULT VIEW STATES
        selectedCounterText = (TextView) findViewById(R.id.selected_counter);
        appName = (TextView) findViewById(R.id.app_name);
        selectedCounterText.setVisibility(View.GONE);
        appName.setVisibility(View.VISIBLE);
        noBulletsMessage = (TextView) findViewById(R.id.noBullets_message);
        noBulletsMessage.setVisibility(View.GONE);

        toolbar = (Toolbar) findViewById(R.id.toolbar);
        setSupportActionBar(toolbar);

        //RECYCLERVIEW PROPERTIES
        recyclerView = (RecyclerView) findViewById(R.id.recyclerView);
        layoutManager = new LinearLayoutManager(this);
        recyclerView.setLayoutManager(layoutManager);
        recyclerView.setItemAnimator(new DefaultItemAnimator());
        recyclerView.setHasFixedSize(true);

        //ACTION MODE ON LONG CLICK VIEW STATES
        selectedCounterText = (TextView) findViewById(R.id.selected_counter);
        selectedCounterText.setVisibility(View.GONE);

        //ADAPTER
        adapter = new CardAdapter(this, bullets);

        //RETRIEVE DATA
        retrieveData();
    }

    @Override
    public boolean onCreateOptionsMenu(Menu menu) {
        getMenuInflater().inflate(R.menu.menu_activity_main, menu);

        //SEARCH
        final MenuItem searchItem = menu.findItem(R.id.item_search);
        searchView = (SearchView) searchItem.getActionView();
        searchView.setIconifiedByDefault(true);
        searchView.setOnCloseListener(new SearchView.OnCloseListener() {
            @Override
            public boolean onClose() {
                return false;
            }
        });
        searchView.setOnQueryTextListener(new SearchView.OnQueryTextListener() {
            @Override
            public boolean onQueryTextSubmit(String query) {
                return false;
            }

            @Override
            public boolean onQueryTextChange(String query) {
                //FILTER AS YOU TYPE
                adapter.getFilter().filter(query);
                return false;
            }
        });

        return true;
    }

    @Override
    protected void onResume() {
        super.onResume();
        retrieveData();
    }

    /**
     * @param item
     * @return This method includes behavior for all action toolbar menu items: Add, search, edit,
     * and delete.
     * <p>
     * It detects which button is pressed and performs the appropriate action.
     */
    @Override
    public boolean onOptionsItemSelected(MenuItem item) {

            //IF HOME (BACK ARROW) IS PRESSED
        } else if (item.getItemId() == android.R.id.home) {
            clearActionMode();
            adapter.notifyDataSetChanged();
        }

        return true;
    }

    public void clearActionMode() {
        isInActionMode = false;
        toolbar.getMenu().clear();
        toolbar.inflateMenu(R.menu.menu_activity_main);
        getSupportActionBar().setDisplayHomeAsUpEnabled(false);
        selectedCounterText.setVisibility(View.GONE);
        appName.setVisibility(View.VISIBLE);
        selectedCounterText.setText("0 Item(s) Selected");
        counter = 0;
        selectedBullets.clear();
    }

    @Override
    public void onBackPressed() {
        if (isInActionMode) {
            clearActionMode();
            adapter.notifyDataSetChanged();
        } else {
            super.onBackPressed();
        }
    }
}

CardHolder.java

public CardHolder(final View itemView, final MainActivity mainActivity) {
        super(itemView);
        signifier_img = (ImageView) itemView.findViewById(R.id.img_id);
        titleText = (TextView) itemView.findViewById(R.id.title);
        categoryText = (TextView) itemView.findViewById(R.id.category);
        cardView = (CardView) itemView.findViewById(R.id.bulletCardView);
        checkBox = (CheckBox) itemView.findViewById(R.id.check_list_item);
        this.mainActivity = mainActivity;

        //CLICK LISTENERS
        cardView.setOnLongClickListener(new View.OnLongClickListener() {
            @Override
            public boolean onLongClick(View view) {
                mainActivity.toolbar.getMenu().clear();
                mainActivity.toolbar.inflateMenu(R.menu.menu_action_mode);
                mainActivity.selectedCounterText.setVisibility(View.VISIBLE);
                mainActivity.appName.setVisibility(View.GONE);
                mainActivity.isInActionMode = true;
                mainActivity.adapter.notifyDataSetChanged();
                mainActivity.getSupportActionBar().setDisplayHomeAsUpEnabled(true);

                return true;
            }
        });
        cardView.setOnClickListener(this);
        checkBox.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View view) {
                mainActivity.prepareSelection(view, getAdapterPosition());
            }
        });

    }

    @Override
    public void onClick(View view) {
        this.itemClickListener.onItemClick(view, getLayoutPosition());
    }

    public void setItemClickListener(ItemClickListener itemClick) {
        this.itemClickListener = itemClick;
    }
}

CardAdapter.java

public class CardAdapter extends RecyclerView.Adapter<CardHolder> implements Filterable {

    Context context;
    ArrayList<Bullet> bullets, filterList;
    SearchFilter filter;
    MainActivity mainActivity;

    public CardAdapter(Context context, ArrayList<Bullet> bullets) {
        this.context = context;
        this.bullets = bullets;
        this.filterList = bullets;
        mainActivity = (MainActivity) context;
    }

    //INITIALIZE VIEWHOLDER
    @Override
    public CardHolder onCreateViewHolder(ViewGroup parent, int viewType) {
        //VIEW OBJ FROM XML
        View view = LayoutInflater.from(parent.getContext()).inflate(R.layout.layout_card_view, parent, false);

        //HOLDER
        CardHolder holder = new CardHolder(view, mainActivity);

        return holder;
    }

    //BIND DATA TO VIEWS
    @Override
    public void onBindViewHolder(final CardHolder holder, int position) {
        holder.signifier_img.setImageResource(R.drawable.asterisk_48px);
        holder.titleText.setText(bullets.get(position).getTitle());

        if (!mainActivity.isInActionMode) {
            holder.checkBox.setVisibility(View.GONE);
        } else {
            holder.checkBox.setVisibility(View.VISIBLE);
            holder.checkBox.setChecked(false);
        }

        //CARD CLICKED
        holder.setItemClickListener(new ItemClickListener() {
            @Override
            public void onItemClick(View view, int position) {
                //DISPLAY POPUP OF FULL INFO OF BULLET
                //OPEN DETAIL VIEW
                //PASS DATA TO VIEW

                if (!mainActivity.isInActionMode) {
                    //CREATE INTENT
                    Intent intent = new Intent(context, DetailView.class);

                    //LOAD DATA TO INTENT
                    intent.putExtra("ID", bullets.get(position).getId());
                    intent.putExtra("TITLE", bullets.get(position).getTitle());
                    intent.putExtra("CATEGORY", bullets.get(position).getCategory());
                    intent.putExtra("SIGNIFIER", bullets.get(position).getSignifier());
                    intent.putExtra("DATE", bullets.get(position).getDate());
                    intent.putExtra("RECURS", bullets.get(position).getRecurs());
                    intent.putExtra("DETAILS", bullets.get(position).getDetails());

                    //START ACTIVITY
                    context.startActivity(intent);
                } else {
                    //DO NOTHING
                }
            }
        });
    }

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

    //RETURN FILTER OBJ
    @Override
    public Filter getFilter() {
        if (filter == null) {
            filter = new SearchFilter(filterList, this);
        }

        return filter;
    }
}

SearchFilter.java

public class SearchFilter extends Filter {

    CardAdapter adapter;
    ArrayList<Bullet> filterList;

    public SearchFilter(ArrayList<Bullet> filterList, CardAdapter adapter) {
        this.adapter = adapter;
        this.filterList = filterList;
    }

    //FILTER OCCURS HERE
    @Override
    protected FilterResults performFiltering(CharSequence constraint) {
        FilterResults results = new FilterResults();

        //CHECK CONSTRAINT VALIDITY
        if (constraint != null && constraint.length() > 0) {

            //CHANGE TO UPPER
            constraint = constraint.toString().toUpperCase();

            //STORE FILTERED BULLETS
            ArrayList<Bullet> filteredBullets = new ArrayList<>();

            for (int i = 0; i < filterList.size(); i++) {
                //CHECK
                if (filterList.get(i).getTitle().toUpperCase().contains(constraint)) {
                    //ADD BULLET TO FILTERED BULLETS
                    filteredBullets.add(filterList.get(i));
                }
            }

            results.count = filteredBullets.size();
            results.values = filteredBullets;

        } else {
            results.count = filterList.size();
            results.values = filterList;
        }

        return results;
    }

    @Override
    protected void publishResults(CharSequence constraint, FilterResults results) {
        adapter.bullets = (ArrayList<Bullet>) results.values;

        //REFRESH RECYCLERVIEW
        adapter.notifyDataSetChanged();
    }
}

menu_activity_main.xml

<?xml version="1.0" encoding="utf-8"?>
<menu xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto">

    <item
        android:id="@+id/item_search"
        android:icon="@drawable/ic_action_search"
        android:title="Search..."
        app:actionViewClass="android.support.v7.widget.SearchView"
        app:showAsAction="collapseActionView|ifRoom" />

    <item
        android:id="@+id/item_add"
        android:icon="@drawable/ic_action_add2"
        android:title="Add"
        app:showAsAction="always" />

</menu>

I believe that's all the code that affects it, but if there's anything else you need let me know.

Here's the Stack Trace:

I don't really understand what it means, but it's what occurs when I try to filter some query after a LongClick Event.

09-07 01:46:38.184 17027-17104/com.curtiswhite.www.sqlitedatabaseforephemeris I/OpenGLRenderer: Initialized EGL, version 1.4 09-07 01:47:40.066 17027-17027/com.curtiswhite.www.sqlitedatabaseforephemeris E/SpannableStringBuilder: SPAN_EXCLUSIVE_EXCLUSIVE spans cannot have a zero length 09-07 01:47:40.066 17027-17027/com.curtiswhite.www.sqlitedatabaseforephemeris E/SpannableStringBuilder: SPAN_EXCLUSIVE_EXCLUSIVE spans cannot have a zero length 09-07 01:47:45.036 17027-17027/com.curtiswhite.www.sqlitedatabaseforephemeris E/SpannableStringBuilder: SPAN_EXCLUSIVE_EXCLUSIVE spans cannot have a zero length 09-07 01:47:45.036 17027-17027/com.curtiswhite.www.sqlitedatabaseforephemeris E/SpannableStringBuilder: SPAN_EXCLUSIVE_EXCLUSIVE spans cannot have a zero length 09-07 01:47:45.991 17027-17027/com.curtiswhite.www.sqlitedatabaseforephemeris W/IInputConnectionWrapper: beginBatchEdit on inactive InputConnection 09-07 01:47:45.991 17027-17027/com.curtiswhite.www.sqlitedatabaseforephemeris W/IIn putConnectionWrapper: getSelectedText on inactive InputConnection 09-07 01:47:46.003 17027-17027/com.curtiswhite.www.sqlitedatabaseforephemeris W/IInputConnectionWrapper: endBatchEdit on inactive InputConnection 09-07 01:47:46.003 17027-17027/com.curtiswhite.www.sqlitedatabaseforephemeris W/IInputConnectionWrapper: getTextBeforeCursor on inactive InputConnection 09-07 01:47:46.015 17027-17027/com.curtiswhite.www.sqlitedatabaseforephemeris W/IInputConnectionWrapper: getTextAfterCursor on inactive InputConnection 09-07 01:47:46.022 17027-17027/com.curtiswhite.www.sqlitedatabaseforephemeris W/IInputConnectionWrapper: beginBatchEdit on inactive InputConnection 09-07 01:47:46.023 17027-17027/com.curtiswhite.www.sqlitedatabaseforephemeris W/IInputConnectionWrapper: getSelectedText on inactive InputConnection 09-07 01:47:46.023 17027-17027/com.curtiswhite.www.sqlitedatabaseforephemeris W/IInputConnectionWrapper: endBatchEdit on inactive InputConnection 09-07 01:47:46.023 17027-17027/com.curti swhite.www.sqlitedatabaseforephemeris W/IInputConnectionWrapper: getTextBeforeCursor on inactive InputConnection 09-07 01:47:46.024 17027-17027/com.curtiswhite.www.sqlitedatabaseforephemeris W/IInputConnectionWrapper: getTextAfterCursor on inactive InputConnection 09-07 01:47:46.027 17027-17027/com.curtiswhite.www.sqlitedatabaseforephemeris W/IInputConnectionWrapper: beginBatchEdit on inactive InputConnection 09-07 01:47:46.027 17027-17027/com.curtiswhite.www.sqlitedatabaseforephemeris W/IInputConnectionWrapper: getSelectedText on inactive InputConnection 09-07 01:47:46.027 17027-17027/com.curtiswhite.www.sqlitedatabaseforephemeris W/IInputConnectionWrapper: endBatchEdit on inactive InputConnection 09-07 01:47:46.028 17027-17027/com.curtiswhite.www.sqlitedatabaseforephemeris W/IInputConnectionWrapper: getTextBeforeCursor on inactive InputConnection 09-07 01:47:46.030 17027-17027/com.curtiswhite.www.sqlitedatabaseforephemeris W/IInputConnectionWrapper: getTextAfterCursor on inactive Inp utConnection 09-07 01:47:46.062 17027-17027/com.curtiswhite.www.sqlitedatabaseforephemeris W/IInputConnectionWrapper: beginBatchEdit on inactive InputConnection 09-07 01:47:46.062 17027-17027/com.curtiswhite.www.sqlitedatabaseforephemeris W/IInputConnectionWrapper: getSelectedText on inactive InputConnection 09-07 01:47:46.062 17027-17027/com.curtiswhite.www.sqlitedatabaseforephemeris W/IInputConnectionWrapper: endBatchEdit on inactive InputConnection 09-07 01:47:46.063 17027-17027/com.curtiswhite.www.sqlitedatabaseforephemeris W/IInputConnectionWrapper: getTextBeforeCursor on inactive InputConnection 09-07 01:47:46.063 17027-17027/com.curtiswhite.www.sqlitedatabaseforephemeris W/IInputConnectionWrapper: getTextAfterCursor on inactive InputConnection

I solved the issue.

It turns out that the issue was caused when inflating the new menu onLongClick. This caused the SearchView to deflate (as expected), but upon pressing back (OnBackPressed gets called), the original menu would inflate, but the SearchView that was placed there was a new one which had not been instantiated.

To correct this, I simply called OnCreateMenuOptions(toolbar.getMenu()); in the onBackPressed method. This reinstantiates the SearchView so it will work again after the menu inflates.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

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