Skip to content
seethaa edited this page Jun 10, 2018 · 30 revisions

We have a series of tasks for building out SeasonalClone, an Android app to help you get a list of seasonal fruits and veggies in your area (In these tasks, we'll be using California as an example).

Check out https://bit.ly/2J31WqQ to see the original app. It is only meant to work in the United States.

You can refer to the task walkthroughs on the right if necessary, but we recommend trying out each of these tasks on your own first.

There are links for relevant reading under each of the tasks to help you out.

Task 1: Load a RecyclerView with test data

Here, we just want to create a recyclerview and adapter and get it to work with some test data.

0. Stick to portrait-mode.

For this project, let's stick to portrait mode.

1. Create an item_produce.xml layout that shows produce name and produce type underneath in the recycler view. Something like this:

item_produce

2. Create a recyclerview to hold your data.

3. Create a data model for ProduceItem with name, type, and description. You will be needing this to populate a list of ProduceItems into the recyclerview.

Kotlin Data Classes

4. Use bindView/Kotterknife for binding views using KotterKnife at https://github.com/JakeWharton/kotterknife

You can just copy ButterKnife.kt into your project: ButterKnife.kt

What's ButterKnife?

In your MainActivity, make sure you use it to bind to the RecyclerView.

5. Use a RecyclerView/adapter for loading data

  • Create the adapter for loading a list of ProduceItems.

  • We'll need to inflate view in our adapter, and it seems useful to create as an extension function if we'll be reusing it. Try creating an extension function for Context.inflate for the situation where you need to use LayoutInflater.from(this).inflate(resource, root, attachToRoot) in your adapter.

RecyclerView/Adapters in Java

Kotlin Extensions

6. Create a list of fake ProduceItems and populate into the recycler view.

Set up MainActivity to populate your RecyclerView, and add some fake data through the adapter.

Here's some sample test data:

//set up test data
val items = listOf(ProduceItem("Apples", "Fruit", "Apples are red."),
        ProduceItem("Bananas", "Fruit", "Bananas are tasty."),
        ProduceItem("Broccoli", "Vegetable", "Broccoli looks like little trees."),
        ProduceItem("Carrot", "Vegetable", "Bunnies like carrots."))

You should now have an app that loads these basic items in a recyclerview. Something that looks like:

task1_finished

Oh, you can remove the FAB. You won't need it.


Task 2: Load In-season Produce for California in June

We have a seasonal_metadata JSON file that contains data for produce items, and a seasonal_california json file for produce items specific to California. We want to use these files to load real produce items for California. Specifically, we only want to show items that are in-season for June!

1. Add both files (seasonal_metadata.json and seasonal_california.json) to assets directory

Check out both files and see the type of data they have and how they are connected.

2. Add Google gson (github.com/google/gson) to build.gradle. We'll use this for parsing JSON data.

Google GSON

3. Fill in your ProduceItem model to mimic the JSON files. Allow GSON to deserialize your JSON into fields using @SerializedName for your client models.

Kotlin Data Class With GSON Example

4. Parse seasonal_metadata JSON file into a list of ProduceItems.

Use AssetManager to open file, and parse JSON:

    val assetManager = context.assets
    val metadataFile = assetManager.open("seasonal_metadata.json")
    val metadata = metadataFile.readBytes().toString(Charset.defaultCharset())

In order to parse the JSON file, use GSONBuilder:

val gsonBuilder = GsonBuilder().setPrettyPrinting().create()

//parse seasonal_metadata
val produceItemList: List<ProduceItem> = gsonBuilder.fromJson(jsonString, object :
   TypeToken<List<ProduceItem>>() {}.type)

5. Populate your RecyclerView with ProduceItems in June for California. All produce names and descriptions are in seasonal_metadata, and California items are in seasonal_california. You can connect them by id. Hint: try map and filter

In MainActivity’s onCreate(), replace fake data with the real list of ProduceItems.

At this point, if you run the app, you should be able to see a list of all of the ProduceItems from the metadata file.

Now, we want to only see produce in June for California, so let's deserialize more data classes.

Mimic the json structure, and you will be able to come up with data classes that encapsulate all of the JSON fields.

Then, fix your parsing method to parse seasonal_california and apply a map/filter to only show California items in June.

Run the app, and you should see a list of California produce items with either "Fruit" or "Vegetable" produce type.

task2_complete


Task 3: Show Images and Add Filters For Fruits and Veggies Sections

We now want to show images of the produce next to the name/type of produce. Then, we will go ahead and divide the fruits and veggies into sections using a title, and display them in the recyclerview.

1. We want to show images for the produce!

  • Add an ImageView to the item_produce.xml layout.

  • Add image property to ProduceItem if you haven't already.

  • Use Glide to populate your ImageViews. Make sure to add INTERNET permission to your Manifest!

How to Use Glide You can use glide version 4.4.0 instead.

If that all went well, you should see a list of produce items with images!

task3_complete

2. Group produce types “Herb”, “Legume”, “Nut”, and “Vegetable" all under Veggies section, and “Fruit” type into the Fruits section. The section headers should be “Fruits” and “Veggies”

  • Create an item_header.xml layout for the section headers.

3. Modify your adapter to use getItemViewType and create a heterogeneous layout with Veggies section and Fruits section.

Heterogeneous Layouts

4. Oh no! Some puppy images got mixed into the produce images. Use a filter to only show items with display = true value in metadata

Here's an example of what it should look like at the end:

task1_complete2 task4_complete1

*Bonus: Show items that are “new” this month as a separate section. Then, use month picker to dynamically load what's new this month based on the month selected.


Task 4: Replace Views With Custom Views

This task will not have any functional difference from Task 3, but custom views are pretty common in most Android projects, so we'll be practicing them. Let's start by using custom views for item_produce.xml and item_header.xml.

1. Create a custom view called BrowseItemView that holds the items from item_produce. This new view can be used by RecyclerView/adapter to load data.

Custom Views in Kotlin

2. Create a custom HeaderItemView for item_header.xml layout for the section headers.

This should be pretty similar to your BrowseItemView in terms of setup.

3. Modify your adapter to use getItemViewType and create a heterogeneous layout with Veggies section and Fruits section. Look into using the SimpleViewHolder class that we discussed so that you don't need to generate multiple ViewHolders.

Here's an example of what it should look like at the end:

task1_complete2 task4_complete1

*Bonus: Show items that are “new” this month as a separate section. Then, use month picker to dynamically load what's new this month based on the month selected.

**Bonus: Use a viewpager to show fruits in one tab, and veggies in another tab.

Clone this wiki locally