You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Kotlin+Retrofit API调用:书籍数组数据模型构建与解析求助

Hey there! Let's break this down step by step since you're new to Kotlin/Android and OOP—no worries, we'll start from the basics and clear up those confusions first.

First: Clearing Up class vs object Confusion

This is a super common point of confusion for folks new to Kotlin, so let's get it straight:

  • object in Kotlin is a singleton—there's only ever one instance of it in your app. This is great for things like a global Retrofit instance, utility helpers, or constant values, but not for data models (like your book details). Each book in the API's array is a separate piece of data with its own unique values, so we need multiple instances—this is where class comes in.
  • Specifically, we'll use Kotlin's data class—it's built exactly for holding structured data, and automatically generates useful methods like equals(), hashCode(), and toString() for you, saving tons of boilerplate code you'd have to write manually in other languages.
Step 1: Add Retrofit Dependencies

First, you need to add Retrofit and a JSON converter to your app's build file (Module-level build.gradle or build.gradle.kts):

// Retrofit core library
implementation "com.squareup.retrofit2:retrofit:2.9.0"
// Gson converter to parse JSON responses into Kotlin objects
implementation "com.squareup.retrofit2:converter-gson:2.9.0"

You can use newer versions if you want, but these are stable and widely used.

Step 2: Define Your Data Model (Match the API Structure)

Let's assume your API returns a JSON array like this:

[
  {
    "id": 1,
    "title": "The Great Gatsby",
    "author": "F. Scott Fitzgerald",
    "page_count": 180
  },
  {
    "id": 2,
    "title": "1984",
    "author": "George Orwell",
    "page_count": 328
  }
]

We'll create a data class that mirrors this structure. If the JSON uses snake_case keys (like page_count), use the @SerializedName annotation to map it to a camelCase property in Kotlin:

import com.google.gson.annotations.SerializedName

data class Book(
    val id: Int,
    val title: String,
    val author: String,
    @SerializedName("page_count") val pageCount: Int
)

Since the API returns an array, our Retrofit call will return a List<Book>.

Step 3: Create a Retrofit Service Interface

This interface defines the exact API call you want to make:

import retrofit2.Call
import retrofit2.http.GET

interface BookApiService {
    // Replace the endpoint path with your actual API's path (e.g., "/api/v1/books")
    @GET("books/details")
    // Returns a Call wrapping a List<Book> (for callback-style calls)
    fun getBookDetails(): Call<List<Book>>

    // For Kotlin Coroutines (recommended for Android, cleaner than callbacks)
    @GET("books/details")
    suspend fun getBookDetailsCoroutine(): List<Book>
}

Coroutines are the modern, recommended way to handle async work in Android, so we'll focus on that next.

Step 4: Initialize Retrofit (Using object the Right Way)

We only need one instance of Retrofit in our app, so we'll use an object (singleton) to create and hold it:

import retrofit2.Retrofit
import retrofit2.converter.gson.GsonConverterFactory

object RetrofitInstance {
    // Replace with your API's base URL (e.g., "https://your-api-domain.com/")
    private const val BASE_URL = "https://api.example.com/"

    val api: BookApiService by lazy {
        Retrofit.Builder()
            .baseUrl(BASE_URL)
            .addConverterFactory(GsonConverterFactory.create())
            .build()
            .create(BookApiService::class.java)
    }
}

This is the correct use case for object—a single, reusable instance that doesn't need multiple copies.

Step 5: Make the API Call (With Coroutines)

In Android, it's best to make API calls from a ViewModel to avoid memory leaks. Here's how to do it:

import androidx.lifecycle.ViewModel
import androidx.lifecycle.viewModelScope
import kotlinx.coroutines.launch

class BookViewModel : ViewModel() {
    fun fetchBooks() {
        // Use viewModelScope to automatically cancel the coroutine if the ViewModel is destroyed
        viewModelScope.launch {
            try {
                // Call the API and get the list of books
                val booksList = RetrofitInstance.api.getBookDetailsCoroutine()
                
                // Success! Use the booksList (it's a List<Book>)
                for (book in booksList) {
                    println("Book: ${book.title} by ${book.author} (${book.pageCount} pages)")
                }
            } catch (e: Exception) {
                // Handle errors (network issues, invalid responses, etc.)
                println("Error fetching books: ${e.message}")
            }
        }
    }
}
Quick Recap to Avoid Future Confusion
  • Use data class for your API data models—each item in the array is a separate instance of this class.
  • Use object only for things that need to be singletons (like the Retrofit instance, utility helpers, or constants).
  • Retrofit handles JSON parsing automatically as long as your data class properties match the API's JSON structure (use @SerializedName if the key names don't align).

内容的提问来源于stack exchange,提问作者Zim

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.22 09:35:10