Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

ListSelector for RecyclerView on touch free device (using onKey Listener)

I am trying to implement a list selector for my RecyclerView grid on a touch free device. My implementation works fine but it requires notifyItemChanged() method which is not efficient performance wise. I have a grid with 100s of items so if i am scrolling fast (scrolling with a keyboard hence the onKey) the grid becomes distorted as lots of items are being updated. Is there a way to avoid this?

Activity

mRecyclerView.setOnKeyListener(new View.OnKeyListener() {
        @Override
        public boolean onKey(View v, int keyCode, KeyEvent event) {
            RecyclerView.LayoutManager lm = mRecyclerView.getLayoutManager();

            if (event.getAction() == KeyEvent.ACTION_DOWN) {
                switch (keyCode) {
                    case Constants.KEYCODE_UP:
                        return moveSelection(lm, -1, true);

                    case Constants.KEYCODE_DOWN:
                        return moveSelection(lm, 1, true);
                }
            }
            return false;
         }   
});

public boolean moveSelection(RecyclerView.LayoutManager lm, int direction, boolean verticalMovement) {
   ...
   //just calculate the position to move to and pass it to selectedPosition
    return mAdapter.tryMoveSelection(lm, selectedPosition);
}

Adapter

 @Override
    public void onBindViewHolder(ViewHolder holder, int position) {
        // - get element from your dataset at this position
        // - replace the contents of the view with that element
        mViewHolder = holder;

        holder.itemView.setSelected(mFocusedItem == position);
        ...
     }

public boolean tryMoveSelection(RecyclerView.LayoutManager lm, int selectedPosition) {
        notifyItemChanged(mFocusedItem);
        mFocusedItem = selectedPosition;
        notifyItemChanged(mFocusedItem);
        lm.scrollToPosition(mFocusedItem);
        return true;
    }
like image 473
stud91 Avatar asked Oct 30 '22 19:10

stud91


1 Answers

There are couple of optimisations you could add to your code:

  1. Don't call notifyItemChanged() when RecyclerView is scrolling. There are couple of handy methods for that:

    • getScrollState() - when the result is different than SCROLL_STATE_IDLE then RecyclerView is scrolling.

    • hasPendingAdapterUpdates() - that means, that RecyclerView.RecyclerAdapter has items to layout.

  2. When the getScrollState() is SCROLL_STATE_IDLE then call notifyItemChanged().

  3. Adapter also has a couple of handy method to override:

    • void onViewAttachedToWindow (VH holder) - is called when view is about to be shown to the user.

    • void onViewDetachedFromWindow (VH holder) - the row is detached from view - free heavy resources here.

like image 183
R. Zagórski Avatar answered Nov 09 '22 13:11

R. Zagórski