Skip to content

[Task 2 Walkthrough]: Load In season Produce for California in June

seethaa edited this page Jun 8, 2018 · 1 revision

Detailed Walkthrough. Only consult this page if you are having difficulty completing the task or wish to check your work.

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

seasonal_metadata.json: https://drive.google.com/file/d/1w5BQOje4-Hqk586gG5OWDH0O_LfPtnFo/view?usp=sharing

seasonal_california.json: https://drive.google.com/open?id=1D0NgqCuaQAr0ilATxE7uulXtgn0rSMVb

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.

// https://github.com/google/gson
implementation 'com.google.code.gson:gson:2.8.2'

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.

Your data class will look similar to this:

data class ProduceItem(
        @SerializedName("ID") val id: String,
        @SerializedName("Name") val name: String,
        @SerializedName("Type") val type: String,
        @SerializedName("Description") val description: String
)

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

Declare the strings for the files:

val SEASONAL_METADATA_JSON = "seasonal_metadata.json"
val SEASONAL_CALIFORNIA_JSON = "seasonal_california.json"

Use AssetManager to open file, and parse JSON:

fun getProduceItemsFromJSON(context: Context): List<ProduceItem> {
    val assetManager = context.assets

    val metadataFile = assetManager.open(SEASONAL_METADATA_JSON)
    val metadata = metadataFile.readBytes().toString(Charset.defaultCharset())

    val stateJSONFile = assetManager.open(SEASONAL_CALIFORNIA_JSON)
    val stateJSONString = stateJSONFile.readBytes().toString(Charset.defaultCharset())
    val produceItems = parseJSONFile(metadata, stateJSONString)

    return produceItems
}

In order to parse the JSON file, use GSONBuilder:

private fun parseJSONFile(jsonString: String, stateJSONString: String): List<ProduceItem> {

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

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

    return produceItemList
}

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 a call to getProduceItemsFromJSON()

//retrieve data from json files
val items = getProduceItemsFromJSON(this)

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 look similar to this:

data class ProduceByState(
        @SerializedName("ID") val id: String,
        @SerializedName("months") val months: ProduceMonth
)
data class ProduceMonth(
        @SerializedName("January") val january: Boolean,
        @SerializedName("February") val february: Boolean,
        @SerializedName("March") val march: Boolean,
        @SerializedName("April") val april: Boolean,
        @SerializedName("May") val may: Boolean,
        @SerializedName("June") val june: Boolean,
        @SerializedName("July") val july: Boolean,
        @SerializedName("August") val august: Boolean,
        @SerializedName("September") val september: Boolean,
        @SerializedName("October") val october: Boolean,
        @SerializedName("November") val november: Boolean,
        @SerializedName("December") val december: Boolean
)

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

private fun parseJSONFile(jsonString: String, stateJSONString: String): List<ProduceItem> {

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

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

    //parse seasonal_california
    val californiaProduceIds: List<ProduceByState> = gsonBuilder.fromJson(stateJSONString, object :
            TypeToken<List<ProduceByState>>() {}.type)


    val juneIds = californiaProduceIds.filter { it -> it.months.june }
            .map { it -> it.id }


    val juneProduce = produceItemList.filter { it -> (juneIds.contains(it.id)) }

    return juneProduce
}

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

task2_complete


You can checkout the solution branch at solutions/task2-loadRealData