android - 使用 Ktor 反序列化 Json 数组的问题

标签 android kotlin ktor kotlinx.serialization

我正在尝试使用 Ktor 和 Kotlinx 序列化从 jsonplaceholder.typicode.com ( here ) 中提取一些虚拟帖子数据并反序列化数组。但是,我收到以下错误:

Error:Expected class kotlinx.serialization.json.JsonObject (Kotlin reflection is not available) as the serialized body of kotlinx.serialization.Polymorphic<List>, but had class kotlinx.serialization.json.JsonArray (Kotlin reflection is not available)

我在代码中的哪个位置指定我期望数据为 JsonObjects 而不是 JsonArrays?这可能是错误,但我没有看到我在代码中指定的位置。

预先感谢您的帮助。

相关代码贴在这里:

LoginRegisterFragment.kt

package com.example.groupupandroid

import android.content.Intent
import android.os.Bundle
import androidx.fragment.app.Fragment
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import androidx.lifecycle.lifecycleScope
import androidx.navigation.Navigation
import androidx.navigation.fragment.findNavController
import com.example.groupupandroid.databinding.ActivityMainBinding
import com.example.groupupandroid.databinding.FragmentLoginRegisterBinding
import data.remote.PostResponse
import data.remote.PostsService
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.GlobalScope
import kotlinx.coroutines.coroutineScope
import kotlinx.coroutines.launch

class LoginRegisterFragment : Fragment(){
    // Getting xml objects
    private var binding: FragmentLoginRegisterBinding? = null
    // Creating service for networking
    private lateinit var service: PostsService

    private var posts: List<PostResponse> = emptyList()

    //@Composable
    override fun onCreateView(
        inflater: LayoutInflater, container: ViewGroup?,
        savedInstanceState: Bundle?
    ): View? {
        binding = FragmentLoginRegisterBinding.inflate(layoutInflater)

        lifecycleScope.launch {getPosts()}

        // Inflate the layout for this fragment
        return binding?.root
    }

    private suspend fun getPosts() {
        service = PostsService.create()
        posts = service.getPosts()
        print(posts)
    }

    override fun onViewCreated(view: View, savedInstanceState: Bundle?) {

        // If register button is tapped make register visible
        binding?.registerToggleButton?.setOnClickListener {
            binding?.registerFields?.visibility = View.VISIBLE
            binding?.loginFields?.visibility = View.GONE
        }

        // If login button is tapped make login visible
        binding?.loginToggleButton?.setOnClickListener {
            binding?.registerFields?.visibility = View.GONE
            binding?.loginFields?.visibility = View.VISIBLE
        }

        // If login button is pushed swap to maps
        binding?.loginButton?.setOnClickListener {
            findNavController().navigate(R.id.loginToHomeScreen)
        }

        // If register button is pushed swap to maps
        binding?.registerButton?.setOnClickListener {
            findNavController().navigate(R.id.loginToHomeScreen)
        }

        binding?.materialButtonToggleGroup?.check(binding?.loginToggleButton!!.id)
    }

    override fun onDestroyView() {
        super.onDestroyView()
        binding = null
    }
}

PostResponse.kt

package data.remote

import kotlinx.serialization.Serializable

@Serializable
data class PostResponse (
    val body: String,
    val title: String,
    val id: Int,
    val userId: Int
)

PostsServiceImplementation.kt

package data.remote

import io.ktor.client.*
import io.ktor.client.call.*
import io.ktor.client.request.*
import io.ktor.client.statement.*
import io.ktor.http.*
import io.ktor.util.*
import java.lang.Exception

class PostsServiceImplementation(private val client: HttpClient): PostsService
 {
    override suspend fun getPosts(): List<PostResponse> {
        return try {
            client.get {url(HttpRoutes.POSTS)}.body()
        } catch(e: Exception){
            println("Error:${e.message}")
            emptyList()
        }
    }

    override suspend fun createPosts(postRequest: PostRequest): PostResponse? {
        return try {
            client.post {
                url(HttpRoutes.POSTS)
                contentType(ContentType.Application.Json)
                setBody(postRequest)
            }.body()
        } catch(e: Exception) {
            println("Error:${e.message}")
            null
        }
    }
}

编辑:更多相关代码。

HttpRoutes.kt

package data.remote

object HttpRoutes {

    private const val BASE_URL = "https://jsonplaceholder.typicode.com"

    const val POSTS = "$BASE_URL/posts"
}

PostsService.kt

package data.remote

import io.ktor.client.*
import io.ktor.client.engine.android.*
import io.ktor.client.plugins.contentnegotiation.*
import io.ktor.client.plugins.kotlinx.serializer.*
import io.ktor.client.plugins.logging.*
import io.ktor.client.statement.*
import io.ktor.serialization.kotlinx.json.*

interface PostsService {

    suspend fun getPosts(): List<PostResponse>

    suspend fun createPosts(postRequest: PostRequest): PostResponse?

    companion object {
        fun create():PostsService {
            return PostsServiceImplementation (
                client = HttpClient(Android) {
                    install(Logging) {
                        level = LogLevel.ALL
                    }
                    install(ContentNegotiation) {
                        json()
                    }
                }
            )
        }
    }
}

PostRequest.kt

package data.remote

import kotlinx.serialization.Serializable

@Serializable
data class PostRequest (
    val body: String,
    val title: String,
    val userId: Int
)

最佳答案

我要结束这个问题了。发现我的数据类上显示以下消息:“kotlinx.serialization 编译器插件未应用于该模块,因此不会处理此注释。请确保您已正确设置构建脚本并重新导入项目”。问题是我没有在我的 build.gradle.kts (应用程序)中包含以下行

    kotlin("plugin.serialization") version "1.7.10"

我也使用了 ProGuard,但没有包含对 ProGuard 规则的相关更改(请参阅 here )。

关于android - 使用 Ktor 反序列化 Json 数组的问题,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/73171936/

相关文章:

android - 如何通过 String 数组 android 扩展自定义 listView 项目超过 10 个项目?

java - 字符串数组列表未正确传递到另一个类的数组列表以显示在下拉列表中

android - 从服务更新搜索栏

kotlin - Ktor HttpClient JsonFeature 可以使用 kotlinx.serialization

kotlin - 如何在Ktor(Kotlin)中的管道的各个部分之间传递数据

java - 转换并显示UTF8编码字符串

generics - Kotlin 泛型更改返回类型

android - finally block 错误 "Variable reader must be initialised"

android - 下载文件列表为空

kotlin - 如何使用 KTOR 库配置 ssl?