如何使用 Kotlin 将 JsonObjectRequest 元素保存在变量中?

Posted

技术标签:

【中文标题】如何使用 Kotlin 将 JsonObjectRequest 元素保存在变量中?【英文标题】:How can I save JsonObjectRequest elements in variables using Kotlin? 【发布时间】:2021-10-06 07:08:04 【问题描述】:

我正在尝试从 mysql 数据库中获取数据,而我的代码正确地获取了数据。 问题是我在 JsonObjectRequest 中有信息,但我无法使用它。我的想法是使用变量来保存我需要的一些信息。 像这样的:

        val queue=Volley.newRequestQueue(this)
        val jsonObjectRequest = JsonObjectRequest(
            Request.Method.GET,url,null,
             response ->
                emailGet = response.getString("email")
                usernameGet = response.getString("name")
            ,  error ->
                Toast.makeText(this, error.toString(), Toast.LENGTH_LONG).show()
            
        )
        queue.add(jsonObjectRequest)

正如我所说,这里的问题是 emailGet 和 usernameGet(在此代码块之前声明的变量)仅将值存储在 JsonObjectRequest 中,其中变量为空。 示例:

        val queue=Volley.newRequestQueue(this)
        val jsonObjectRequest = JsonObjectRequest(
            Request.Method.GET,url,null,
             response ->
                emailGet = response.getString("email")
                usernameGet = response.getString("name")
                Toast.makeText(this, emailGet, Toast.LENGTH_LONG).show()
            ,  error ->
                Toast.makeText(this, error.toString(), Toast.LENGTH_LONG).show()
            
        )
        queue.add(jsonObjectRequest)
        Toast.makeText(this, usernameGet, Toast.LENGTH_LONG).show()

这里 Toast 将只在屏幕上打印 emailGet 内容,因为它在 JsonObjectRequest 中,必须打印 usernameGet 值的 Toast 不会这样做。

查找信息我发现这个问题可能是因为这个函数是异步的,我在 Java 中找到了一个可能的解决方案,我尝试将其翻译为 Kotlin。

        val queue=Volley.newRequestQueue(this)
        val future : RequestFuture<JSONObject> = RequestFuture.newFuture()
        val request = JsonObjectRequest(
            Request.Method.GET, url, null, future, future)

        queue.add(request)
        try
            var response = future.get()
         catch (e : InterruptedException)
         catch (e : ExecutionException)
        

我不是很理解第二个代码,但它仍然无法正常工作,响应变量始终为空,并且程序在该尝试中停留在无限循环中。

【问题讨论】:

您说响应和错误回调是异步的是正确的,因此在您的第一个代码 sn-p 中,最终的 toast 语句可能在收到响应之前运行。如果您想使用emailGetusernameGet 变量,您可能希望在回调中执行此操作。您是否有理由不想/不能这样做? @ttyip 嗨,是的,我需要在代码的其他部分使用它们。 “在其他部分使用它们”是指在收到响应后直接使用这些数据,还是希望存储它们并在需要时使用它们?前者很简单,只需将数据传递给使用变量的方法即可;对于后者,您需要持久存储它们并在以后检索它们。 @ttyip 在收到回复后我暂时需要它。如何将数据传递给其他方法?我什至不能在 JsonObjectRequest 下的相同方法中使用它 【参考方案1】:

如果你想使用emailGetusernameGet 变量,你应该在回调中进行:

val queue = Volley.newRequestQueue(this)
val jsonObjectRequest = JsonObjectRequest(
    Request.Method.GET, url, null,
     response ->
        emailGet = response.getString("email")
        usernameGet = response.getString("name")

        // TODO do something with the variables here
    ,  error ->
        Toast.makeText(this, error.toString(), Toast.LENGTH_LONG).show()
    
)

queue.add(jsonObjectRequest)

如果相反,您有一个方法方法 doSomething() 在收到响应后立即运行:

fun doSomething(email:String, username:String)
    // TODO do something with the variables here

您可以将第一个代码 sn-p 中的 TODO 注释替换为doSomething(emailGet, usernameGet)


JsonObjectRequest 的第 4 和第 5 个参数实际上是 Response.ListenerResponse.ErrorListener 类型的对象。这两个听众是Single Abstract Method interfaces。如果展开它会是这样的:

val jsonObjectRequest = JsonObjectRequest(
    Request.Method.GET, url, null,
    object : Response.Listener 
        override fun onResponse(response: JSONObject) 
            emailGet = response.getString("email")
            usernameGet = response.getString("name")

            doSomething(emailGet, usernameGet)
        
    ,
    object : Response.ErrorListener 
        override fun onErrorResponse(error: VolleyError) 
            Toast.makeText(this, error.toString(), Toast.LENGTH_LONG).show()
        
    
)

您使用的 lambda 语法是 SAM 接口的简写。

【讨论】:

【参考方案2】:

最简单的方法是使用@ttyip 的答案,但您也可以使用实时数据并观察它!你正在调用一个异步方法,并且会有一些延迟(网络 API 调用,这个延迟取决于用户的互联网连接等)所以首先你需要在你的项目中添加 jetPack 的 lifeCycle 组件:

dependencies 
    def lifecycle_version = "2.4.0-alpha02"

    implementation "androidx.lifecycle:lifecycle-livedata-ktx:$lifecycle_version"

    // Annotation processor
    kapt "androidx.lifecycle:lifecycle-compiler:$lifecycle_version"
    // alternately - if using Java8, use the following instead of lifecycle-compiler
    implementation "androidx.lifecycle:lifecycle-common-java8:$lifecycle_version"

同步您的项目后,在您的活动/片段中定义全局:

val email: MutableLiveData<String> = MutableLiveData<String>()
val username: MutableLiveData<String> = MutableLiveData<String>()

在您的回复中:

 val jsonObjectRequest = JsonObjectRequest(
        Request.Method.GET,url,null,
         response ->
            val emailGet = response.getString("email")
            val usernameGet = response.getString("name")
            email.postValue(emailGet)
            username.postValue(usernameGet)
        ,  error ->
            Toast.makeText(this, error.toString(), Toast.LENGTH_LONG).show()
        
    )

在您的活动中的某个地方,只需观察您的实时数据:

email.observe(this, Observer  string ->
 // Do some work 
)
username.observe(this, Observer  string ->
// Do some work 
)

【讨论】:

以上是关于如何使用 Kotlin 将 JsonObjectRequest 元素保存在变量中?的主要内容,如果未能解决你的问题,请参考以下文章

如何使用内容协商将 json 转换为 ktor 中的 kotlin 对象?

如何使用 java / kotlin 中的注释处理将方法附加到现有类?

如何在 Kotlin 中使用协程将图像保存在设备中

如何将 java 库添加到 kotlin 本机

Kotlin 中如何使用 Picasso 将 URL 转换为位图?

如何使用 SpringBoot2、JUnit5 和 Kotlin 将配置属性注入单元测试