预期 BEGIN_ARRAY 但在第 1 行第 2 列路径 BEGIN_OBJECT $ JSON Array Kotlin
Expected BEGIN_ARRAY but was BEGIN_OBJECT at line 1 column 2 path $ JSON Array Kotlin
我想检索一个 JSON 数组,我该如何调整我的代码库以适应它。我使用改造库来检索数据,并使用了 MVVM 架构。我收到错误 Expected BEGIN_ARRAY but was BEGIN_OBJECT at line 1 column 2 path $.
这是我的终点class:
@GET("v2/venues/search")
fun fetchAllVenues(): Call<List<Venue>>
}
这是我的存储库class:
class VenueRepository {
private var apiInterface: VenuesEndpoint? = null
init {
apiInterface = ApiClient.getApiClient().create(VenuesEndpoint::class.java)
}
fun fetchAllVenues(): MutableLiveData<List<Venue>?> {
val data = MutableLiveData<List<Venue>?>()
apiInterface?.fetchAllVenues()?.enqueue(object : Callback<List<Venue>> {
override fun onFailure(call: Call<List<Venue>>, t: Throwable) {
data.value = null
}
override fun onResponse(
call: Call<List<Venue>>,
response: Response<List<Venue>>
) {
val res = response.body()
if (response.code() == 200 && res != null) {
data.value = res
} else {
data.value = null
}
}
})
return data
}
}
这是我的模型class:
data class Venue(var id:Int,var name:String)
这是我的视图模型class:
class VenueViewModel : ViewModel() {
private var venueRepository: VenueRepository? = null
var postModelListLiveData: MutableLiveData<List<Venue>?>? = null
init {
venueRepository = VenueRepository()
postModelListLiveData = MutableLiveData()
}
fun fetchAllVenues() {
postModelListLiveData = venueRepository?.fetchAllVenues()
}
}
这是我要检索的 JSON:
"response": { "venues": [ { "id": "4b83cb72f964a520d71031e3" "name": "Stadhuis" "contact": { "phone": "+3114010" "formattedPhone": "+31 14010" "twitter": "rotterdam" } "location": { "address": "Coolsingel 40" "lat": 51.92258962728412 "lng": 4.480227190204032 "labeledLatLngs": [ "0": { "label": "display" "lat": 51.92258962728412 "lng": 4.480227190204032 } ] "postalCode": "3011 AD" "cc": "NL" "city": "Rotterdam" "state": "Zuid-Holland" "country": "Nederland" "formattedAddress": [ "0": "Coolsingel 40" "1": "3011 AD Rotterdam" "2": "Nederland"
问题是,响应 return 是你 venues
并且你期待 List<Venue>
,所以对你有用的是,创建另一个数据 class就像这样:
data class Venues(
val venues: List<Venue>
)
然后在GET
请求里面returnCall<Venues>
请告诉我这是否为您解决了 :)
更新
好吧,谈话有点冗长,但最后这是您的详细解决方案,希望这能为您解决所有问题!
ViewModel
import androidx.lifecycle.LiveData
import androidx.lifecycle.ViewModel
class ViewModel : ViewModel() {
private val repository = Repository()
fun getData(longLat: String, date: String): LiveData<mainResponse?> {
repository.fetch(longLat, date)
return repository.data
}
}
Repository
import androidx.lifecycle.LiveData
import androidx.lifecycle.MutableLiveData
import retrofit2.Call
import retrofit2.Callback
import retrofit2.Response
class Repository {
private val _data: MutableLiveData<mainResponse?> = MutableLiveData(null)
val data: LiveData<mainResponse?> get() = _data
fun fetch(longlat: String, date: String) {
val retrofit = Retro()
val api = retrofit.retro.create(api::class.java)
api.get(
longLat = longlat,
date = date
).enqueue(object : Callback<mainResponse>{
override fun onResponse(call: Call<mainResponse>, response: Response<mainResponse>) {
val res = response.body()
if (response.code() == 200 && res != null) {
_data.value = res
} else {
_data.value = null
}
}
override fun onFailure(call: Call<mainResponse>, t: Throwable) {
_data.value = null
}
})
}
}
MainActivity
private val viewModel by viewModels<ViewModel>()
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
viewModel.getData(
longLat = "40.7,-74", // sample latitude and longitude
date = "20210715" // date format is: YYYYMMDD
).observe(this, Observer {
it?.let { res ->
res.response.venues.forEach { venue ->
val name = venue.name
val location = venue.location
Log.d("name ",name)
Log.d("address ", location.address)
}
}
})
}
}
Api Interface
import retrofit2.Call
import retrofit2.http.GET
import retrofit2.http.Query
interface api {
@GET("v2/venues/search")
fun get(
@Query("ll") longLat: String,
@Query("client_id") id: String = Const.clientId,
@Query("client_secret") secret: String = Const.clientSecret,
@Query("v") date: String
): Call<mainResponse>
}
Model Classes
mainResponse
数据class mainResponse(
val响应:响应
)
Response
data class Response(
val venues: List<Venue>,
val confident: Boolean
)
Location
data class Location(
val address: String,
val crossStreet: String,
val lng: Double,
val lat: Double
)
Venue
data class Venue(
val id: String,
val name: String,
val location: Location
)
Const
object Const {
const val BASE_URL = "https://api.foursquare.com"
const val clientId = "" // add yours
const val clientSecret = "" // add yours
}
Retro
class Retro {
val retro = Retrofit.Builder()
.baseUrl(Const.BASE_URL)
.addConverterFactory(GsonConverterFactory.create())
.build()
}
Dependencies: make sure to add activity-ktx for using ViewModel in activity
def coroutines_version = "1.4.2"
implementation "org.jetbrains.kotlinx:kotlinx-coroutines-core:$coroutines_version"
implementation "org.jetbrains.kotlinx:kotlinx-coroutines-android:$coroutines_version"
implementation "org.jetbrains.kotlinx:kotlinx-coroutines-play-services:$coroutines_version"
def lifecycle_version = "2.3.1"
implementation "androidx.lifecycle:lifecycle-livedata-ktx:$lifecycle_version"
implementation "androidx.lifecycle:lifecycle-viewmodel-ktx:$lifecycle_version"
implementation "androidx.lifecycle:lifecycle-runtime-ktx:$lifecycle_version"
def retrofit_version = "2.9.0"
implementation "com.squareup.retrofit2:retrofit:$retrofit_version"
implementation "com.squareup.retrofit2:converter-gson:$retrofit_version"
implementation "androidx.activity:activity-ktx:1.2.3"
我想检索一个 JSON 数组,我该如何调整我的代码库以适应它。我使用改造库来检索数据,并使用了 MVVM 架构。我收到错误 Expected BEGIN_ARRAY but was BEGIN_OBJECT at line 1 column 2 path $.
这是我的终点class:
@GET("v2/venues/search")
fun fetchAllVenues(): Call<List<Venue>>
}
这是我的存储库class:
class VenueRepository {
private var apiInterface: VenuesEndpoint? = null
init {
apiInterface = ApiClient.getApiClient().create(VenuesEndpoint::class.java)
}
fun fetchAllVenues(): MutableLiveData<List<Venue>?> {
val data = MutableLiveData<List<Venue>?>()
apiInterface?.fetchAllVenues()?.enqueue(object : Callback<List<Venue>> {
override fun onFailure(call: Call<List<Venue>>, t: Throwable) {
data.value = null
}
override fun onResponse(
call: Call<List<Venue>>,
response: Response<List<Venue>>
) {
val res = response.body()
if (response.code() == 200 && res != null) {
data.value = res
} else {
data.value = null
}
}
})
return data
}
}
这是我的模型class:
data class Venue(var id:Int,var name:String)
这是我的视图模型class:
class VenueViewModel : ViewModel() {
private var venueRepository: VenueRepository? = null
var postModelListLiveData: MutableLiveData<List<Venue>?>? = null
init {
venueRepository = VenueRepository()
postModelListLiveData = MutableLiveData()
}
fun fetchAllVenues() {
postModelListLiveData = venueRepository?.fetchAllVenues()
}
}
这是我要检索的 JSON:
"response": { "venues": [ { "id": "4b83cb72f964a520d71031e3" "name": "Stadhuis" "contact": { "phone": "+3114010" "formattedPhone": "+31 14010" "twitter": "rotterdam" } "location": { "address": "Coolsingel 40" "lat": 51.92258962728412 "lng": 4.480227190204032 "labeledLatLngs": [ "0": { "label": "display" "lat": 51.92258962728412 "lng": 4.480227190204032 } ] "postalCode": "3011 AD" "cc": "NL" "city": "Rotterdam" "state": "Zuid-Holland" "country": "Nederland" "formattedAddress": [ "0": "Coolsingel 40" "1": "3011 AD Rotterdam" "2": "Nederland"
问题是,响应 return 是你 venues
并且你期待 List<Venue>
,所以对你有用的是,创建另一个数据 class就像这样:
data class Venues(
val venues: List<Venue>
)
然后在GET
请求里面returnCall<Venues>
请告诉我这是否为您解决了 :)
更新
好吧,谈话有点冗长,但最后这是您的详细解决方案,希望这能为您解决所有问题!
ViewModel
import androidx.lifecycle.LiveData
import androidx.lifecycle.ViewModel
class ViewModel : ViewModel() {
private val repository = Repository()
fun getData(longLat: String, date: String): LiveData<mainResponse?> {
repository.fetch(longLat, date)
return repository.data
}
}
Repository
import androidx.lifecycle.LiveData
import androidx.lifecycle.MutableLiveData
import retrofit2.Call
import retrofit2.Callback
import retrofit2.Response
class Repository {
private val _data: MutableLiveData<mainResponse?> = MutableLiveData(null)
val data: LiveData<mainResponse?> get() = _data
fun fetch(longlat: String, date: String) {
val retrofit = Retro()
val api = retrofit.retro.create(api::class.java)
api.get(
longLat = longlat,
date = date
).enqueue(object : Callback<mainResponse>{
override fun onResponse(call: Call<mainResponse>, response: Response<mainResponse>) {
val res = response.body()
if (response.code() == 200 && res != null) {
_data.value = res
} else {
_data.value = null
}
}
override fun onFailure(call: Call<mainResponse>, t: Throwable) {
_data.value = null
}
})
}
}
MainActivity
private val viewModel by viewModels<ViewModel>()
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
viewModel.getData(
longLat = "40.7,-74", // sample latitude and longitude
date = "20210715" // date format is: YYYYMMDD
).observe(this, Observer {
it?.let { res ->
res.response.venues.forEach { venue ->
val name = venue.name
val location = venue.location
Log.d("name ",name)
Log.d("address ", location.address)
}
}
})
}
}
Api Interface
import retrofit2.Call
import retrofit2.http.GET
import retrofit2.http.Query
interface api {
@GET("v2/venues/search")
fun get(
@Query("ll") longLat: String,
@Query("client_id") id: String = Const.clientId,
@Query("client_secret") secret: String = Const.clientSecret,
@Query("v") date: String
): Call<mainResponse>
}
Model Classes
mainResponse
数据class mainResponse( val响应:响应 )
Response
data class Response(
val venues: List<Venue>,
val confident: Boolean
)
Location
data class Location(
val address: String,
val crossStreet: String,
val lng: Double,
val lat: Double
)
Venue
data class Venue(
val id: String,
val name: String,
val location: Location
)
Const
object Const {
const val BASE_URL = "https://api.foursquare.com"
const val clientId = "" // add yours
const val clientSecret = "" // add yours
}
Retro
class Retro {
val retro = Retrofit.Builder()
.baseUrl(Const.BASE_URL)
.addConverterFactory(GsonConverterFactory.create())
.build()
}
Dependencies: make sure to add activity-ktx for using ViewModel in activity
def coroutines_version = "1.4.2"
implementation "org.jetbrains.kotlinx:kotlinx-coroutines-core:$coroutines_version"
implementation "org.jetbrains.kotlinx:kotlinx-coroutines-android:$coroutines_version"
implementation "org.jetbrains.kotlinx:kotlinx-coroutines-play-services:$coroutines_version"
def lifecycle_version = "2.3.1"
implementation "androidx.lifecycle:lifecycle-livedata-ktx:$lifecycle_version"
implementation "androidx.lifecycle:lifecycle-viewmodel-ktx:$lifecycle_version"
implementation "androidx.lifecycle:lifecycle-runtime-ktx:$lifecycle_version"
def retrofit_version = "2.9.0"
implementation "com.squareup.retrofit2:retrofit:$retrofit_version"
implementation "com.squareup.retrofit2:converter-gson:$retrofit_version"
implementation "androidx.activity:activity-ktx:1.2.3"