Join Chiu-Ki Chan for an in-depth discussion in this video RecyclerView, part of Effective Android Testing for Mobile Developers.
- [Instructor] Now that we have a RecipeStore, let's use that in our app. This part is not strictly related to testing, but I want to show you all the steps of building this app so that you can see when to add tests. As you have already seen, it is very useful to write tests along the way rather than wait until the very end. We will display the recipes in a RecyclerView. To do that, we'll need to add that as a dependency.
Go to app/build.gradle. In the dependency block, go to line 23, and press Command + D to duplicate. Replace appcompat-v7 with recyclerview-v7. Click Sync Now to perform a gradle sync. Next, open the resource folder. In layout, open activity_main.
Change the TextView to be a RecyclerView. Give it the id recipes and the padding of 8dp. To populate the RecyclerView with recipes, we need to create a ViewHolder and an Adapter. Click on the main activity on the file directory. It will be under Java, ui.main.
Right-click on the folder, New, Java Class. Call it RecipeViewHolder. We will need to extend this from RecyclerView.ViewHolder, extends RecyclerView.ViewHolder. Press Alt + Enter, and choose Create constructor. Our item itself will be a TextView, so cast is to a TextView and assign it to a field, textView equal the cast of TextView and then the itemView.
Point your cursor at textView, the variable, Alt + Enter, and Create field. Change this field to public. Next, we will create the Adapter. Again, right-click on the ui.main folder, New, Java Class. We will call it RecipeAdapter. This time, we will make it extend RecyclerView.Adapter. The Adapter will take the type RecipeViewHolder that we just created.
Alt + Enter, and choose Implement methods. We will choose them all and press OK. In onCreateViewHolder, we will need to inflate a view for each of the item in the RecyclerView. To do that, we will need to create a layout file. Click on the layout folder under res, right-click, select New, Layout resource file. We will call it list item and change the root element to be a TextView.
Click on the Text tab, and then we are going to change this TextView so that it has the parameters we want. I usually like to make it close on itself, so I will add a slash at the end of line five. It comes with the default parameters of layout width and height of match parent, but we want to change the height to be wrap content. Next, we want to add the parameter gravity as center vertical and then padding of 4dp, textSize as 18sp, and finally we will set the background android:background, and then the value is going to be ?attr/selectableItemBackground.
Now that we have defined our list item, let's go back to the Adapter. In line nine, we are going to inflate the list item that we just created. View, give it a name view, equal LayoutInflater.from, and then we'll need the context, which we can obtain from the parent, parent.getContext. Then go to the end, and call inflate. We will give it the parameter R.layout.list item and then parent, and then the ViewGroup will be false.
Next, we'll return a new ViewHolder with this view, return new RecipeViewHolder, view. Next, we will implement the function onBindViewHolder. OnCreateViewHolder inflates the view, but doesn't put any data in it. We will do that in onBindViewHolder. To do that, we will need to have a RecipeStore. So let's make that a field and then also pass that in, in the constructor.
We'll make a constructor public RecipeAdapter, and then it will take in the RecipeStore as the parameter. Call it store. In the body, we will assign the store to a field, this.store equal store. Right-click on the red word so that we can create a field. Go back to onBindViewHolder. And in line 27, we are going to retrieve a recipe out of the store, final Recipe, call it recipe, equal store.recipes.get position.
The position is the parameter that got passed in in the function. This means that we are going to look into the store and find the matching position of the recipe and retrieve it. Now that we have a recipe, we can populate the ViewHolder. In the ViewHolder, there's a textView. We are going to call setText on it with the recipe title. Finally, we need to implement getItemCount. Go to line 34.
And instead of returning the default value of zero, we'll return store.recipes.size. Now that we have created RecipeViewHolder and RecipeAdapter, we can use that in the main activity to display the recipes.
- Why test?
- Local vs. on-device
- Code coverage
- UI testing
- Hermetic environment
- Dependency injection
- Testing with MVP