title: Android recyclerview-selection Implementation?
body: <p>I'm currently trying to implement the new <code>recyclerview-selection</code> APIs from Android Support Library 28.0.0-alpha1, and am running into some issues. My goal is to have a <code>RecyclerView</code>, with the ability to select multiple rows, show a Contextual Action Bar, and perform actions on them, such as &quot;delete&quot; or &quot;share&quot;</p>
  <p>I'll try and furnish enough code to give a good idea of what's going on, but I can always respond with more if necessary.</p>
  <p>In my <code>Fragment</code> which contains the <code>RecyclerView</code> I'm concerned with, I am initiating a <code>SelectionTracker</code>, and setting it on my <code>RecyclerView.Adapter</code>, like so:</p>
  <pre class="lang-java prettyprint-override"><code>private void buildRecyclerView() {
      sheetsAdapter = new SheetsAdapter(getContext(), this, sheets);
      gridManager = new GridLayoutManager(getContext(), getResources().getInteger(R.integer.grid_span_count));
  
      ItemOffsetDecoration itemDecoration = new ItemOffsetDecoration(getContext(), R.dimen.item_offset);
      sheetsRecycler.addItemDecoration(itemDecoration);
      sheetsRecycler.setLayoutManager(gridManager);
      sheetsRecycler.setAdapter(sheetsAdapter);
      sheetsRecycler.setHasFixedSize(true);
  
      SelectionTracker selectionTracker = new SelectionTracker.Builder&lt;&gt;(
          &quot;sheet_selection&quot;,
          sheetsRecycler,
          new StableIdKeyProvider(sheetsRecycler),
          new SheetDetailsLookup(sheetsRecycler),
          StorageStrategy.createLongStorage()
      )
      .withOnContextClickListener(this)
      .build();
  
      sheetsAdapter.setSelectionTracker(selectionTracker);
  }
  </code></pre>
  <p>This <code>Fragment</code> also <code>implements OnContextClickListener</code>, in order to listen for long-clicks on the items in my <code>RecyclerView</code>:</p>
  <pre class="lang-java prettyprint-override"><code>@Override
  public boolean onContextClick(@NonNull MotionEvent e) {
      if (actionMode != null) {
          return false;
      }
  
      // Start the CAB using the ActionMode.Callback defined below
      if (getActivity() != null) {
          actionMode = ((AppCompatActivity) getActivity()).startSupportActionMode(actionModeCallback);
      }
  
      return true;
  }
  </code></pre>
  <p>And it <em>should</em> show my CAB, like this:</p>
  <pre class="lang-java prettyprint-override"><code>private ActionMode.Callback actionModeCallback = new ActionMode.Callback() {
  
      @Override
      public boolean onCreateActionMode(ActionMode mode, Menu menu) {
          MenuInflater inflater = mode.getMenuInflater();
          inflater.inflate(R.menu.sheets_cab_menu, menu);
  
          return true;
      }
  
      @Override
      public boolean onPrepareActionMode(ActionMode mode, Menu menu) {
          return false;
      }
  
      @Override
      public boolean onActionItemClicked(ActionMode mode, MenuItem item) {
          switch (item.getItemId()) {
              case  R.id.delete:
                  Toast.makeText(getContext(), R.string.sheets_delete, Toast.LENGTH_SHORT).show();
                  mode.finish();
                  return true;
              default:
                  return false;
          }
      }
  
      @Override
      public void onDestroyActionMode(ActionMode mode) {
          actionMode = null;
      }
  };
  </code></pre>
  <p>My <code>SheetDetailsLookup</code> looks like this:</p>
  <pre class="lang-java prettyprint-override"><code>public class SheetDetailsLookup extends ItemDetailsLookup&lt;Long&gt; {
  
      private RecyclerView recyclerView;
  
      SheetDetailsLookup(RecyclerView recyclerView) {
          super();
  
          this.recyclerView = recyclerView;
      }
  
      @Nullable
      @Override
      public ItemDetails&lt;Long&gt; getItemDetails(@NonNull MotionEvent e) {
          View view = recyclerView.findChildViewUnder(e.getX(), e.getY());
          if (view != null) {
              RecyclerView.ViewHolder holder = recyclerView.getChildViewHolder(view);
              if (holder instanceof SheetsAdapter.SheetViewHolder) {
                  return ((SheetsAdapter.SheetViewHolder) holder).getItemDetails();
              }
          }
          return null;
      }
  }
  </code></pre>
  <p>And in my <code>SheetViewHolder</code>, I update the view to show that it has been selected:</p>
  <pre class="lang-java prettyprint-override"><code>if (selectionTracker.isSelected(sheet.uid)) {
      layout.setBackgroundResource(R.color.md_grey_700);
  } else {
      layout.setBackgroundResource(android.R.color.transparent);
  }    
  </code></pre>
  <p>As well as:</p>
  <pre class="lang-java prettyprint-override"><code>public SheetItemDetails getItemDetails() {
      return new SheetItemDetails(getAdapterPosition(), mSheets.get(getAdapterPosition()).uid);
  }   
  </code></pre>
  <p>Where <code>SheetItemDetails</code> is simply:</p>
  <pre class="lang-java prettyprint-override"><code>public class SheetItemDetails extends ItemDetailsLookup.ItemDetails&lt;Long&gt; {
  
      private int position;
      private Long key;
  
      SheetItemDetails(int position, Long key) {
          this.position = position;
          this.key = key;
      }
  
      @Override
      public int getPosition() {
          return position;
      }
  
      @Nullable
      @Override
      public Long getSelectionKey() {
          return key;
      }
  }
  </code></pre>
  <p>I've implemented all of the things mentioned in the <a href="https://developer.android.com/reference/androidx/recyclerview/selection/package-summary.html" rel="nofollow noreferrer">API specification</a>, but am now running into troubles. My CAB doesn't show up when I select an item... and the app usually crashes. Crashes occur whenever I try to &quot;back out&quot; of selections,and then long-click to start another selection, with this stack trace:</p>
  <pre><code>java.lang.IllegalStateException
      at android.support.v4.util.Preconditions.checkState(Preconditions.java:130)
      at android.support.v4.util.Preconditions.checkState(Preconditions.java:142)
      at androidx.recyclerview.selection.GestureSelectionHelper.start(GestureSelectionHelper.java:76)
      at androidx.recyclerview.selection.SelectionTracker$Builder$4.run(SelectionTracker.java:742)
      at androidx.recyclerview.selection.TouchInputHandler.onLongPress(TouchInputHandler.java:136)
      at androidx.recyclerview.selection.GestureRouter.onLongPress(GestureRouter.java:95)
      at android.view.GestureDetector.dispatchLongPress(GestureDetector.java:779)
      at android.view.GestureDetector.access$200(GestureDetector.java:40)
      at android.view.GestureDetector$GestureHandler.handleMessage(GestureDetector.java:293)
      at android.os.Handler.dispatchMessage(Handler.java:106)
      at android.os.Looper.loop(Looper.java:164)
      at android.app.ActivityThread.main(ActivityThread.java:6656)
      at java.lang.reflect.Method.invoke(Native Method)
      at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:438)
      at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:823)
  </code></pre>
  <p>Also, I've now lost the ability to &quot;short-click&quot; on one of my items, to launch a detail view... Which I had working just fine until now.</p>
  <p>What have I done wrong?</p>