【问题标题】:Kotlin - How to read JSON string on urlKotlin - 如何读取 url 上的 JSON 字符串
【发布时间】:2018-03-20 22:01:46
【问题描述】:

我是 Kotlin 的新手,我找到了 Klaxon 库来解析 JSON。我找不到如何执行 url(http://localhost:8080/items/2)、读取 JSON 字符串并将数据保存到变量并将它们打印到控制台。 CreatedAt 和 UpdatedAt 我不需要保存。

来自 url 的 JSON:

{
    "brand": "Ferrero",
    "name": "Nutella",
    "healthy": false,
    "date": "2017-03-14T00:00:00.000Z",
    "id": 2,
    "createdAt": "2018-03-14T13:33:22.000Z",
    "updatedAt": "2018-03-20T21:23:44.000Z"
}

代码:

class DetailItem : AppCompatActivity()  {
    var itemId : String = ""
    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_detail_item)
        itemId = intent.getStringExtra("itemId")
    }

    override fun onResume() {
        super.onResume()
        example()
    }

    private fun parse(name: String) : Any{
        val cls = Parser::class.java
        val inputStream = cls.getResourceAsStream(name)!!
        return Parser().parse(inputStream)!!
    }

    private fun example(){
        val url = "http://192.168.99.100:8080/items/" + itemId
        val obj = parse("url") as JsonObject

        val brand = obj.string("brand")
        val name = obj.string("name")
        println(brand + name)
    }

【问题讨论】:

  • 到目前为止你写过代码吗? Here's the documentation for Klaxon
  • 对不起,我的回答迟了。我添加了代码。错误是:kotlin.KotlinNullPointerException
  • 哪一行抛出异常?
  • at DetailItem.parse(val inputStream = cls.getResourceAsStream(name)!!) at DetailItem.example(val obj = parse("url") as JsonObject) at DetailItem.onResume(example() )
  • 不应该 parse("url")parse(url) 吗?不确定这是否足够,但这似乎是一个有问题的错字

标签: kotlin klaxon


【解决方案1】:

问题是cls.getResourceAsStream(name) 方法返回null,而!! 运算符会导致NPE 被抛出。

为什么cls.getResourceAsStream(name) 返回null?发生这种情况是因为方法 getResourceAsStream 在您在项目中提供的资源中使用提供的 name 搜索资源(即文件)。

但是,在您的情况下,您想从 URL 下载 JSON,因此您需要首先执行下载,这将为您提供 String 形式的 JSON(或可以转换为 @ 987654329@),然后用Parser().parse(yourJsonString) as JsonObject解析那个字符串。

编辑

这是一个使用 OkHttp 库的示例:

import com.beust.klaxon.Klaxon
import okhttp3.Call
import okhttp3.Callback
import okhttp3.OkHttpClient
import okhttp3.Request
import okhttp3.Response
import java.io.IOException

fun main(args: Array<String>) {
    val url = "https://jsonplaceholder.typicode.com/posts/1"

    val client = OkHttpClient()
    val request = Request.Builder()
        .url(url)
        .build()

    println(Thread.currentThread())
    client.newCall(request).enqueue(object : Callback {
        override fun onFailure(call: Call?, e: IOException?) {
            e?.printStackTrace()
        }

        override fun onResponse(call: Call?, response: Response) {
            if (!response.isSuccessful) {
                System.err.println("Response not successful")
                return
            }
            val json = response.body()!!.string()
            val myData = Klaxon().parse<MyData>(json)
            println("Data = $myData")
            println(Thread.currentThread())
        }

    })
    // Shutdown the executor as soon as the request is handled
    client.dispatcher().executorService().shutdown()
}

data class MyData(val title: String, val userId: Int)

REST API 返回的 JSON 字符串是:

{
  "userId": 1,
  "id": 1,
  "title": "sunt aut facere repellat provident occaecati excepturi optio reprehenderit",
  "body": "quia et suscipitsuscipit recusandae consequuntur expedita et cumreprehenderit molestiae ut ut quas totamnostrum rerum est autem sunt rem eveniet architecto"
}

该代码打印:

Thread[main,5,main]
Data = MyData(title=sunt aut facere repellat provident occaecati excepturi optio reprehenderit, userId=1)
Thread[OkHttp https://jsonplaceholder.typicode.com/...,5,main]

请注意,onResponse 回调在工作线程上执行,而不是在主线程上执行,因此如果您在 Android 中使用此代码,您将无法从那里更改 UI 元素(除非您使用 @987654335 @ 或类似技术)

【讨论】:

  • 是否有解决方案如何读取 url 上的 json,就像我发布的问题一样?如果没有,如何下载url并保存为json文件?
  • 当然,您需要使用 http 客户端(或更高级别的东西,如改造)来调用您的服务器并检索响应。之后可以保存到文件或者直接解析
  • 我发布了新的答案来解决我的问题,但它是 AsyncTask,如何重写它并只在我想要的时候执行它?
  • AsyncTask 是一种方法,当您想要执行类似new MyAsyncTask().execute(...) 的操作时执行它。以后可以给你更详细的回答,以防万一
  • @misolo89 我加了一个例子
【解决方案2】:

我发现这段代码可以解决我的问题。但它是AsyncTask,如何重写,只在需要时才执行?

inner class AsyncTaskHandleJson : AsyncTask<String, String, String>() {
        override fun doInBackground(vararg url: String?): String {

            var text: String
            var connection = URL(url[0]).openConnection() as HttpURLConnection
            try {
                connection.connect()
                text = connection.inputStream.use { it.reader().use { reader -> reader.readText() } }
            } finally {
                connection.disconnect()
            }

            return text
        }

        override fun onPostExecute(result: String?) {
            super.onPostExecute(result)
            handleJson(result)
        }
    }

    private fun handleJson(jsonString: String?) {

        val jsonObject = JSONObject(jsonString)

        val itemIdBrand = findViewById<TextView>(R.id.itemIdBrand)
        itemIdBrand.text = jsonObject.getString("brand")

        println(jsonObject.getString("brand"))
    }

【讨论】:

  • “重写”是什么意思,只在需要时执行?同时,您可以从谷歌阅读这个解释清楚的 AsyncTask 对象文档:developer.android.com/reference/android/os/AsyncTask.html
  • 如果我理解正确的话,AsyncTask 只有在我调用MyAsyncTask().execute(...) 时才会执行?
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2011-07-30
  • 1970-01-01
  • 2017-11-26
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多