Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Android Robolectric Click RecyclerView Item

Is there any way to simulate a click on a RecyclerView item with Robolectric?

So far, I have tried getting the View at the first visible position of the RecyclerView, but that is always null. It's getChildCount() keeps returning 0, and findViewHolderForPosition is always null. The adapter returns a non-0 number from getItemCount() (there are definitely items in the adapter).

I'm using Robolectric 2.4 SNAPSHOT.

like image 969
Eliezer Avatar asked Nov 21 '14 01:11

Eliezer


4 Answers

Seems like the issue was that RecyclerView needs to be measured and layed out manually in Robolectric. Calling this solves the problem:

recyclerView.measure(0, 0);
recyclerView.layout(0, 0, 100, 10000);
like image 103
Eliezer Avatar answered Nov 13 '22 20:11

Eliezer


With Robolectric 3 you can use visible():

ActivityController<MyActivity> activityController = Robolectric.buildActivity(MyActivityclass);
activityController.create().start().visible();

ShadowActivity myActivityShadow = shadowOf(activityController.get()); 

RecyclerView currentRecyclerView = ((RecyclerView) myActivityShadow.findViewById(R.id.myrecyclerid));
    currentRecyclerView.getChildAt(0).performClick();

This eliminates the need to trigger the measurement of the view by hand.

like image 44
Marco Hertwig Avatar answered Nov 13 '22 19:11

Marco Hertwig


Expanding on Marco Hertwig's answer:

You need to add the recyclerView to an activity so that its layout methods are called as expected. You could call them manually, (like in Elizer's answer) but you would have to manage the state yourself. Also, this would not be simulating an actual use-case.

Code:

@Before
public void setup() {
    ActivityController<Activity> activityController = 
        Robolectric.buildActivity(Activity.class); // setup a default Activity
    Activity activity = activityController.get();

    /*
    Setup the recyclerView (create it, add the adapter, add a LayoutManager, etc.)
    ...
    */

    // set the recyclerView object as the only view in the activity
    activity.setContentView(recyclerView);

    // start the activity
    activityController.create().start().visible();
}

Now you don't need to worry about calling layout and measure everytime your recyclerView is updated (by adding/removing items from the adapter, for example).

like image 2
Vedant Agarwala Avatar answered Nov 13 '22 20:11

Vedant Agarwala


Just invoke

Robolectric.flushForegroundThreadScheduler()

before performClick() to ensure that all ui operations (including measure and layout phases of recycler view after populating with the dataset) are finished

like image 2
Alexander Bernat Avatar answered Nov 13 '22 21:11

Alexander Bernat