Parse JSON Array without Key in Android using Retrofit and Kotlin

huangapple go评论109阅读模式
英文:

Parse JSON Array without Key in Android using Retrofit and Kotlin

问题

I'm here to help with your translation request. Here's the translated content you provided:

我一直在开发一个Android应用程序,我一直在处理API调用/响应等问题。问题在于我收到的API响应已经发生了变化,我无法找到序列化和打包的方法。

这是来自API的旧响应:

[
{
"msg": "此时间段无可用数据:2022-11-14 11:00:00 和 2022-11-14 11:15:00"
},
{
"datetime": "2022-11-14 11:15:00",
"avg_temp": 27.59265899658203,
"min_temp": 27.59265899658203,
"max_temp": 27.59265899658203,
"open_temp": 27.59265899658203,
"close_temp": 27.59265899658203
},
{
"datetime": "2022-11-14 11:30:00",
"avg_temp": 27.59265899658203,
"min_temp": 27.59265899658203,
"max_temp": 27.59265899658203,
"open_temp": 27.59265899658203,
"close_temp": 27.59265899658203
}
]


API响应变成了这样:

[
[
1668413700,
-99,
29,
27.59,
27.59,
27.59,
27.59,
27.59
],
[
1668414600,
-99,
29,
27.59,
27.59,
27.59,
27.59,
27.59
]
]


因此,我已经创建了这样的数据类:

@Parcelize
data class TRA(
@SerializedName("datetime")
val datetime: Long?,
@SerializedName("pred")
val pred: Float?,
@SerializedName("sensor")
val sensor: Int?,
@SerializedName("average")
val average: Float?,
@SerializedName("min")
val min: Float?,
@SerializedName("max")
val max: Float?,
@SerializedName("open")
val open: Float?,
@SerializedName("close")
val close: Float?,
@SerializedName("msg")
val msg: String?
): Parcelable


我还有这样的Repository类,并对其进行了修改以适应新的API响应:

suspend fun uploadId(request: TextRecognitionRequest): List? {
return try {
val response = api.uploadSensorId(request = request)
val jsonArray = JSONArray(response)
val resultList = mutableListOf()
for (i in 0 until jsonArray.length()) {
val json = jsonArray.getJSONArray(i)
val item = TemperatureResponseAggregation(
datetime = json.optInt(0),
pred = json.optDouble(1).toFloat(),
sensor = json.optInt(2),
average = json.optDouble(3).toFloat(),
min = json.optDouble(4).toFloat(),
max = json.optDouble(5).toFloat(),
open = json.optDouble(6).toFloat(),
close = json.optDouble(7).toFloat(),
)
resultList.add(item)
}
resultList

    } catch (e: Exception) {
        e.printStackTrace()
        null
    }
}

这是我的MainActivityViewModel类:

@HiltViewModel
class MainActivityViewModel @Inject constructor(
private val repository: CameraRepository
) : ViewModel() {

private val _sensorResponse = MutableLiveData<List<TRA>>()
val sensorResponse: LiveData<List<TRA>> = _sensorResponse

fun uploadSensorId(request: TextRecognitionRequest) {
    viewModelScope.launch {
        _sensorResponse.postValue(repository.uploadSensorId(request))
    }
}

}


顺便说一下,我像这样使用了Retrofit:
@Provides
@Singleton
fun provideCameraApi(okHttpClient: OkHttpClient): CameraApi {
    return Retrofit.Builder()
        .baseUrl(Constants.BASE_URL)
        .client(okHttpClient)
        .addConverterFactory(GsonConverterFactory.create())
        .build()
        .create(CameraApi::class.java)
}

最后,在我的主活动中,我有一个将这些响应数据写入图表的函数,它如下所示:

```plaintext
private fun lineChartForDataObservation() {
        viewModel.sensorResponse.observe(this) { response ->
            response?.let { safeResponse ->
                val values = arrayListOf<Float>()
                val valuesPred = arrayListOf<Float>()
                val valuesClose = arrayListOf<Float>()
                val valuesOpen = arrayListOf<Float>()
                val valuesMax = arrayListOf<Float>()
                val valuesMin = arrayListOf<Float>()
                dates = arrayListOf()
                val sensors = arrayListOf<Int>()
                for (item in safeResponse) {
                    item.datetime?.let { dates.add(it.toString()) }
                    item.pred?.let { valuesPred.add(it)  }
                    item.average?.let { values.add(it) }
                    item.open?.let { valuesOpen.add(it) }
                    item.close?.let { valuesClose.add(it) }
                    item.min?.let { valuesMin.add(it) }
                    item.max?.let { valuesMax.add(it) }
                }
                chartModels.add(
                    AASeriesElement()
                        .name(sensors.component1().toString())
                        .data(values.toTypedArray())
                        .allowPointSelect(true)
                        .dashStyle(AAChartLineDashStyleType.Solid)
                )
                drawChart()
            } ?: run {
                Toast.makeText(this, "出了点问题!", Toast.LENGTH_LONG).show()
                startActivity(Intent(this, OpenCameraActivity::class.java))
            }
        }
    }

我已经努力并搜索了解决方法,但找不到有用的或有帮助的东西,所以请帮助我了解如何完成这项任务,如果我解释问题不清楚,对此我感到抱歉,我还是个新手。


Please let me know if you need any further assistance!

<details>
<summary>英文:</summary>

I&#39;ve been working on an android app and I&#39;ve been struggling with api calls/responses etc. and the problem is the api response I received and serialized/parcelized it&#39;s been changed and I couldn&#39;t find a way to serialize and parcelize.

This is the old response from api:

[
{
"msg": "No data available for this time period: 2022-11-14 11:00:00 and 2022-11-14 11:15:00"
},
{
"datetime": "2022-11-14 11:15:00",
"avg_temp": 27.59265899658203,
"min_temp": 27.59265899658203,
"max_temp": 27.59265899658203,
"open_temp": 27.59265899658203,
"close_temp": 27.59265899658203
},
{
"datetime": "2022-11-14 11:30:00",
"avg_temp": 27.59265899658203,
"min_temp": 27.59265899658203,
"max_temp": 27.59265899658203,
"open_temp": 27.59265899658203,
"close_temp": 27.59265899658203
}
]


Api response change into this:

[
[
1668413700,
-99,
29,
27.59,
27.59,
27.59,
27.59,
27.59
],
[
1668414600,
-99,
29,
27.59,
27.59,
27.59,
27.59,
27.59
]
]

and so I&#39;ve already created a data class like this:

@Parcelize
data class TRA(
@SerializedName("datetime")
val datetime: Long?,
@SerializedName("pred")
val pred: Float?,
@SerializedName("sensor")
val sensor: Int?,
@SerializedName("average")
val average: Float?,
@SerializedName("min")
val min: Float?,
@SerializedName("max")
val max: Float?,
@SerializedName("open")
val open: Float?,
@SerializedName("close")
val close: Float?,
@SerializedName("msg")
val msg: String?
):Parcelable

and I&#39;ve Repository class like this and I&#39;ve modified like this to work with new api response:

suspend fun uploadId(request: TextRecognitionRequest): List<TRA>? {
return try {
val response = api.uploadSensorId(request = request)
val jsonArray = JSONArray(response)
val resultList = mutableListOf<TRA>()
for (i in 0 until jsonArray.length()) {
val json = jsonArray.getJSONArray(i)
val item = TemperatureResponseAggregation(
datetime = json.optInt(0),
pred = json.optDouble(1).toFloat(),
sensor = json.optInt(2),
average = json.optDouble(3).toFloat(),
min = json.optDouble(4).toFloat(),
max = json.optDouble(5).toFloat(),
open = json.optDouble(6).toFloat(),
close = json.optDouble(7).toFloat(),
)
resultList.add(item)
}
resultList

    } catch (e: Exception) {
        e.printStackTrace()
        null
    }
}
this is my MainActivityViewModel class:

@HiltViewModel
class MainActivityViewModel @Inject constructor(
private val repository: CameraRepository
) : ViewModel() {

private val _sensorResponse = MutableLiveData&lt;List&lt;TRA&gt;&gt;()
val sensorResponse: LiveData&lt;List&lt;TRA&gt;&gt; = _sensorResponse

fun uploadSensorId(request: TextRecognitionRequest) {
    viewModelScope.launch {
        _sensorResponse.postValue(repository.uploadSensorId(request))
    }
}

}


I&#39;m using retrofit by the way like this:
@Provides
@Singleton
fun provideCameraApi(okHttpClient: OkHttpClient): CameraApi {
    return Retrofit.Builder()
        .baseUrl(Constants.BASE_URL)
        .client(okHttpClient)
        .addConverterFactory(GsonConverterFactory.create())
        .build()
        .create(CameraApi::class.java)
}

Finally in my main activity I have a function that writes these response datas into the chart it goes like this:

private fun lineChartForDataObservation() {
viewModel.sensorResponse.observe(this) { response ->
response?.let { safeResponse ->
val values = arrayListOf<Float>()
val valuesPred = arrayListOf<Float>()
val valuesClose = arrayListOf<Float>()
val valuesOpen = arrayListOf<Float>()
val valuesMax = arrayListOf<Float>()
val valuesMin = arrayListOf<Float>()
dates = arrayListOf()
val sensors = arrayListOf<Int>()
for (item in safeResponse) {
item.datetime?.let { dates.add(it.toString()) }
item.pred?.let { valuesPred.add(it) }
item.average?.let { values.add(it) }
item.open?.let { valuesOpen.add(it) }
item.close?.let { valuesClose.add(it) }
item.min?.let { valuesMin.add(it) }
item.max?.let { valuesMax.add(it) }
}
chartModels.add(
AASeriesElement()
.name(sensors.component1().toString())
.data(values.toTypedArray())
.allowPointSelect(true)
.dashStyle(AAChartLineDashStyleType.Solid)
)
drawChart()
} ?: run {
Toast.makeText(this, "Something went wrong!", Toast.LENGTH_LONG).show()
startActivity(Intent(this, OpenCameraActivity::class.java))
}
}
}

I&#39;ve tried and search for a solution for this but couldn&#39;t find anything useful or helpful so please I want to learn how can I do this task, and if I explained my problem badly sorry about it I&#39;m still a newbie at this kind of things.   


**SOLUTION**

I made it worked guys the problem was in my api interface I&#39;ve changed to Object to Array&lt;Array&lt;Double&gt;&gt; it works that way now, thank you for suggestions and helps. I really appreciated  

@POST(&quot;....&quot;)

suspend fun test(
@Header("Accept") header1: String = "....",
@Header("User-Agent") header2: String = "....",

@Header(&quot;Connection&quot;) header5: String= &quot;.....&quot;,
@Body request: .....,

) : Array<Array<Double>>


</details>


# 答案1
**得分**: 0

This is not going to work with the "new api response" since your new api response is an array of arrays of floats.

You'd need something like:

    for (i in 0 until jsonArray.length()) {
        val jsonArrayOfFloats = jsonArray.getJSONArray(i)
        // Parse jsonArrayOfFloats and do something with values

<details>
<summary>英文:</summary>

&gt; and I&#39;ve Repository class like this and I&#39;ve modified like this to work with new api response:

    for (i in 0 until jsonArray.length()) {
        val jsonObject = jsonArray.getJSONObject(i)

This is not going to work with the &quot;new api response&quot; since your new api response is an array of arrays of floats.

You&#39;d need something like:

    for (i in 0 until jsonArray.length()) {
        val jsonArrayOfFloats = jsonArray.getJSONArray(i)
        // Parse jsonArrayOfFloats and do something with values


</details>



huangapple
  • 本文由 发表于 2023年4月10日 22:52:45
  • 转载请务必保留本文链接:https://go.coder-hub.com/75978146.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定