Android Networking: Fundamentals

Sep 6 2022 · Kotlin 1.6, Android 12, Android Studio Chipmunk | 2021.2.1 Patch 1

Part 2: Implement Retrofit Basics

16. Implement the Moshi Parser

Episode complete

Play next episode

Next
About this episode

Leave a rating/review

See forum comments
Cinema mode Mark complete Download course materials
Previous episode: 15. Add Queries to Calls Next episode: 17. Challenge: Work with Moshi Parser

Get immediate access to this and 4,000+ other videos and books.

Take your career further with a Kodeco Personal Plan. With unlimited access to over 40+ books and 4,000+ professional videos in a single subscription, it's simply the best investment you can make in your development career.

Learn more Already a subscriber? Sign in.

Notes: 16. Implement the Moshi Parser

The student materials have been reviewed and are updated as of July 2022.

Transcript: 16. Implement the Moshi Parser

Once again, as you’re going through Retrofit API calls, you saw how the part for parsing data keeps repeating, as well as some other pieces of code.

In the fourth part of the course, you’ll see about shortening the Retrofit code in general, but for now, you’ll see how to make the process of parsing even smoother!

To achieve this, you’ll use another really cool parser, Moshi! Moshi is similar to Gson, and in fact uses quite a lot of the same approaches.

But it is a much lighter parser, takes up less resources, doesn’t use heavy reflection operations to make parsing faster, and supports Kotlin and nullable types out of the box! Let’s see how to use it! :]

You probably guessed what you have to do first! Head over to build.gradle, and add the following dependecy:

implementation "com.squareup.retrofit2:converter-moshi:2.7.1"

Sync the project and head over to the RetrofitBuilders.kt file. Add the following line of code to the Retrofit builder.

.addConverterFactory(MoshiConverterFactory.create().asLenient())

This will add the MoshiConverter to Retrofit, which will automatically parse the JSON, and give the object of the type you need. The asLenient() call here creates a more forgiving parser. Forgiving in a way that you don’t need to parse all the JSON fields for example, that losing data isn’t a problem. Now head over to the RemoteApiService.kt file, and replace the code in the following way:

fun registerUser(@Body request: UserDataRequest): Call<RegisterResponse>

fun loginUser(@Body request: UserDataRequest): Call<LoginResponse>

fun getNotes(@Header("Authorization") token: String): Call<GetTasksResponse>

fun completeTask(
  @Header("Authorization") token: String,
  @Query("id") noteId: String): Call<CompleteNoteResponse>
      
fun addTask(
  @Header("Authorization") token: String,
  @Body request: AddTaskRequest): Call<Task>

Instead of using the Response and Request bodies, you’re using clear types, as Moshi will recognize them, and parse them accordingly. But how will Moshi know in what way it needs to parse the data? To do that, you need to change the request and response models in the following way:

class AddTaskRequest(
    @field:Json(name = "title") val title: String,
    @field:Json(name = "content") val content: String,
    @field:Json(name = "taskPriority") val taskPriority: Int)

You need to add the annotation as in the example, to tell what JSON property name will match the Kotlin object name. You don’t have to do this if the names are exact, but it’s best to name every single property, just to be sure. Then Moshi will follow this convention, and parse everything properly. Now do this for the rest of the models, except for the UserProfile model:

data class UserDataRequest(
    @field:Json(name = "email") val email: String,
    @field:Json(name = "password") val password: String,
    @field:Json(name = "name") val name: String? = null
)
class CompleteNoteResponse(@field:Json(name = "message") val message: String?)
data class GetTasksResponse(@field:Json(name = "notes") val notes: List<Task> = listOf())
data class LoginResponse(@field:Json(name = "token") val token: String? = "")
data class RegisterResponse(@field:Json(name = "message")val message: String? = "")
class Task(
    @field:Json(name = "id") val id: String,
    @field:Json(name = "title") val title: String,
    @field:Json(name = "content") val content: String,
    @field:Json(name = "isCompleted") val isCompleted: Boolean,
    @field:Json(name = "taskPriority") val taskPriority: Int
)

You will change the UserProfile model later in the course. For the final step, change all the RemoteApi.kt functions and code usages, to use clear types like so:

That’s quite the change, but it’ll be worth it. You now have much less code in the API layer, and you don’t have to parse everything yourself.

Instead of using manual parsing in various places, you can now use the response.body(), as Moshi will parse it for you, and put the object you are looking for in the body() property.

Instead of using gson to translate models into json and send them as the RequestBody, you can send the models, and Moshi will take care of that too. And instead of using callbacks of the type ResponseBody, you now use concrete types. Run the project, and everything should work as before!