簡體   English   中英

安卓:Kotlin - Retrofit2 - Moshi | 使用復雜的 json

[英]Android: Kotlin - Retrofit2 - Moshi | working with complex json

我正在嘗試使用此 API 請求獲取游戲列表。 https://steamspy.com/api.php?request=top100forever

但是我相信我的問題是所有游戲都在另一個東西里面,只有 appid。 這就是響應的樣子

{
  "10": {
    "appid": 10,
    "name": "Counter-Strike",
    "developer": "Valve",
    "publisher": "Valve",
    "score_rank": "",
    "positive": 143404,
    "negative": 3739,
    "userscore": 0,
    "owners": "20,000,000 .. 50,000,000",
    "average_forever": 9671,
    "average_2weeks": 815,
    "median_forever": 287,
    "median_2weeks": 925,
    "price": "99",
    "initialprice": "999",
    "discount": "90"
  },
  "30": {
    "appid": 30,
    "name": "Day of Defeat",
    "developer": "Valve",
    "publisher": "Valve",
    "score_rank": "",
    "positive": 3885,
    "negative": 463,
    "userscore": 0,
    "owners": "5,000,000 .. 10,000,000",
    "average_forever": 259,
    "average_2weeks": 0,
    "median_forever": 33,
    "median_2weeks": 0,
    "price": "49",
    "initialprice": "499",
    "discount": "90"
  },
  ....
}

我的 apiService:

private const val BASE_URL_GAMES = "https://steamspy.com/"

private val moshi = Moshi.Builder()
    //.add(ResponseGetGamesAdapter())
    .add(KotlinJsonAdapterFactory())
    .build()

//OkhttpClient for building http request url
private val tmdbClient = OkHttpClient().newBuilder()
    .build()

private val retrofit = Retrofit.Builder()
    .client(tmdbClient)
    .addConverterFactory(MoshiConverterFactory.create(moshi))
    .addCallAdapterFactory(CoroutineCallAdapterFactory())
    .baseUrl(BASE_URL_GAMES)
    .build()


interface GameApiService{
    @GET("api.php?request=top100forever")
    fun getTop100(): Deferred<List<Game>>

}



object GameApi {
    val retrofitService: GameApiService by lazy {
        retrofit.create(GameApiService::class.java)
    }
}

視圖模型

enum class GameApiStatus { LOADING, ERROR, DONE }

class GameOverviewViewModel : ViewModel() {
    // TODO: Implement the
    private val _response = MutableLiveData<String>()
    private val _status = MutableLiveData<GameApiStatus>()

    //private var gameRepository: GameRepository = GameRepository()

    // The external immutable LiveData for the response String
    val response: LiveData<GameApiStatus>
        get() = _status

    private val _properties = MutableLiveData<List<Game>>()
    val properties: LiveData<List<Game>>
        get() = _properties

    // Create a Coroutine scope using a job to be able to cancel when needed
    private var viewModelJob = Job()

    // the Coroutine runs using the Main (UI) dispatcher
    private val coroutineScope = CoroutineScope(viewModelJob + Dispatchers.Main )

    init {
        getTop100()
    }

    private fun getTop100() {
        coroutineScope.launch {
            // Get the Deferred object for our Retrofit request
            var getPropertiesDeferred = GameApi.retrofitService.getTop100()
            try {
                // Await the completion of our Retrofit request
                var listResult = getPropertiesDeferred.await()
                _status.value = GameApiStatus.DONE
                _properties.value = listResult
            } catch (e: Exception) {
                val error = e.message
                _status.value = GameApiStatus.ERROR
                _properties.value = ArrayList()
            }
        }
    }

    /**
     * When the [ViewModel] is finished, we cancel our coroutine [viewModelJob], which tells the
     * Retrofit service to stop.
     */
    override fun onCleared() {
        super.onCleared()
        viewModelJob.cancel()
    }
}

游戲模型

data class Game(
    //var id:Int,
    @field:Json(name = "appid")
    var appid:Int,
    @field:Json(name = "name")
    var name:String
    //var desc:String
)

在這一點上,我一直在苦苦掙扎,我可能在路上弄壞了更多東西,哈哈,我認為我需要某種適配器,但我絕對一無所知。 試圖盡可能接近我們課程中的完成方式,但此時我會采取任何工作方式:D

問題似乎在這里:

interface GameApiService{
@GET("api.php?request=top100forever")
fun getTop100(): Deferred<List<Game>>
}

你在你的代碼中說你會得到一個Game對象的List ,但你的 api 沒有給你。

這是來自您的 api 的響應:

{
  "10": {
    "appid": 10,
    ...
    },
  "30": {
    "appid": 30,
    ...
    }
}

在此示例中,您的 API 返回的是一個對象10 ,其中包含許多其他數據,以及一個對象30 ,其中包含許多其他數據。 似乎1030包含相同的字段,因此可以在以后提供幫助。

這意味着您可以創建一個名為GameServiceResponse的新數據類。

data class GameServiceResponse(
    @Json(name = "10") val 10: Game,
    @Json(name = "30") val 30: Game
)

然后您更改您的GameApiService以接受此響應。 但是,您從一開始就沒有收到List ,因此必須這樣做。

interface GameApiService{
@GET("api.php?request=top100forever")
fun getTop100(): Deferred<GameServiceResponse>
}

最后,當你使用它時,你會得到類似getPropertiesDeferred.10.appid東西

另一件事:由於您使用的是 moshi,我相信您仍然需要告訴 api 類您正在使用 moshi 反序列化(如果您的適配器正在執行此部分,則可能不需要):

interface GameApiService{

@MoshiDeserialization
@GET("api.php?request=top100forever")
fun getTop100(): Deferred<GameServiceResponse>
}

我希望這是有道理的。

嘗試如下更新:更新服務

interface GameApiService{
    @GET("api.php?request=top100forever")
    fun getTop100(): Deferred<Map<String,Game>>
}

然后你會從API中得到map的結果。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM