Day94 of #100DaysOfCode

Kushagra Kesav
4 min readMay 11, 2022
Day94 of #100DaysOfCode

Hii folks 🙌

Today I will be continuing the same pathway in which we will learn to parse the JSON response with Moshi

Unit 4: Internet

Pathway 2: Get and Display Data

https://developer.android.com/courses/android-basics-kotlin/course

Parse the JSON response with Moshi

Add Moshi library dependencies

  • We will open build.gradle (Module: app).
  • In the dependencies section, we will add the code shown below to include the Moshi dependency. This dependency adds support for the Moshi JSON library with Kotlin support.
// Moshi
implementation 'com.squareup.moshi:moshi-kotlin:1.13.0'
  • Locate the lines for the Retrofit scalar converter in the dependencies block and change these dependencies to use converter-moshi:

// Retrofit
implementation "com.squareup.retrofit2:retrofit:2.9.0"
// Retrofit with Moshi Converter
implementation "com.squareup.retrofit2:converter-scalars:2.9.0"

with this

// Retrofit with Moshi Converter
implementation 'com.squareup.retrofit2:converter-moshi:2.9.0'
  • Now, Click Sync Now to rebuild the project with the new dependencies.

Implement the Mars Photos data class

  • A sample entry of the JSON response we get from the web service looks something like this:
[{
"id":"424906",
"img_src":"http://mars.jpl.nasa.gov/msl-raw-images/msss/01000/mcam/1000ML0044631300305227E03_DXXX.jpg"
},
...]

In the example above, we notice that each Mars photo entry has these JSON key and value pairs:

  • id: the ID of the property, as a string. Since it is wrapped in " " it is of the type String not Integer.
  • img_src: The image's URL as a string.

Moshi parses this JSON data and converts it into Kotlin objects. To do this, Moshi needs to have a Kotlin data class to store the parsed results, so in this step we will create the data class, MarsPhoto.

  • Then we do Right-click on the network package and select New > Kotlin File/Class.
  • In the popup, select Class and enter MarsPhoto as the name of the class. This creates a new file called MarsPhoto.kt in the network package.
  • Make MarsPhoto a data class by adding the data keyword before the class definition. Change the {} braces to () parentheses. This leaves us with an error, because data classes must have at least one property defined.
data class MarsPhoto(
)

* We will add the following properties to the MarsPhoto class definition.

data class MarsPhoto(
val id: String, val img_src: String
)

When Moshi parses the JSON, it matches the keys by name and fills the data objects with appropriate values.

@Json Annotation

To use variable names in the data class that differ from the key names in the JSON response, use the @Json annotation. In this example, the name of the variable in the data class is imgSrcUrl. The variable can be mapped to the JSON attribute img_src using @Json(name = "img_src").

  • Replace the line for the img_src key with the line shown below. Import com.squareup.moshi.Json when requested.
@Json(name = "img_src") val imgSrcUrl: String

Update MarsApiService and OverviewViewModel

In this task, we will create a Moshi object using the Moshi Builder, similar to the Retrofit builder.

We will replace ScalarsConverterFactory with the KotlinJsonAdapterFactory to let Retrofit know it can use Moshi to convert the JSON response into Kotlin objects. We will then update the network API and ViewModel to use the Moshi object.

  • Open network/MarsApiService.kt. Notice the unresolved reference errors for ScalarsConverterFactory. This is because of the Retrofit dependency change we made in a previous step. Delete the import for ScalarConverterFactory.

Remove:

import retrofit2.converter.scalars.ScalarsConverterFactory
  • At the top of the file, just before the Retrofit builder, add the following code to create the Moshi object, similar to the Retrofit object.
private val moshi = Moshi.Builder()

Import com.squareup.moshi.Moshi and com.squareup.moshi.kotlin.reflect.KotlinJsonAdapterFactory when requested.

  • For Moshi’s annotations to work properly with Kotlin, in the Moshi builder, add the KotlinJsonAdapterFactory, and then call build().
private val moshi = Moshi.Builder()
.add(KotlinJsonAdapterFactory())
.build()
  • In the retrofit object declaration change the Retrofit builder to use the MoshiConverterFactory instead of the ScalarConverterFactory, and pass in the moshi instance we just created.
private val retrofit = Retrofit.Builder()
.addConverterFactory(MoshiConverterFactory.create(moshi))
.baseUrl(BASE_URL)
.build()

Import retrofit2.converter.moshi.MoshiConverterFactory when requested.

  • Now that we have the MoshiConverterFactory in place, we can ask Retrofit to return a list of MarsPhoto objects from the JSON array instead of returning a JSON string. Update the MarsApiService interface to have Retrofit return a list of MarsPhoto objects, instead of returning String.
interface MarsApiService {
@GET("photos")
suspend fun getPhotos(): List<MarsPhoto>
}
  • Do similar changes to the viewModel, open OverviewViewModel.kt. Scroll down to getMarsPhotos() method.
  • In the method getMarsPhotos(), listResult is a List<MarsPhoto> not a String anymore. The size of that list is the number of photos that were received and parsed. To print the number of photos retrieved update _status.value as follows.
_status.value = "Success: ${listResult.size} Mars photos retrieved"

Import com.example.android.marsphotos.network.MarsPhoto when prompted.

  • Make sure airplane mode is turned off in our device or emulator. Compile and run the app. This time the message should show the number of properties returned from the web service, not a big JSON string

That is all for Day94 ✅

Thanks for reading, See you tomorrow!

--

--