0

I'm trying to take data from a mySQL database and my code take it correctly. The problem is that I have the information in a JsonObjectRequest and out of it, I can't use it. My idea was to use variables to save some of the information I need. Something like this:

        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)

As I said the problem here is that emailGet and usernameGet (variables declared before this code bloc) store the values only inside the JsonObjectRequest, out of it the variables are empty. Example:

        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()

Here the Toast will print on the screen only the emailGet content because it's inside the JsonObjectRequest, the Toast that have to print the usernameGet value will not do it.

Looking for information I have found that this problem could be because this function is asynchronous and I found a possible solution in Java that I tried to translate to 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){
        }

I do not really understand this second code, but it still doesn't working, the response variable is always empty and the program stays in an infinite loop inside that try.

4
  • 1
    You are correct in saying that the response and error callbacks are asynchronous, therefore in your 1st code snippet, the final toast statement probably runs before a response is received. If you want to use the emailGet and usernameGet variables, you probably want to do it within the callback. Is there a reason why you don't want to/can't do that? Commented Jul 30, 2021 at 19:14
  • @ttyip Hi, yes I need to use them in some other parts of my code. Commented Jul 30, 2021 at 19:17
  • 1
    By "use them in some other parts", do you mean you are using this data directly after a response is received, or you'd like to store them and use them when needed? The former is straightforward, just pass the data to the method that uses the variables; For the latter, you would need to persistently store them and retrieve them later. Commented Jul 30, 2021 at 19:22
  • @ttyip For the moment I need it after a response is received. How can i pass the data to other method? I can't even use it in the same method under JsonObjectRequest Commented Jul 30, 2021 at 19:25

2 Answers 2

2

If you want to use the emailGet and usernameGet variables, you should do it within the callback:

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)

If instead, you have a method method doSomething() that runs immediately after the response is received:

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

You can replace the TODO comment in the first code snippet with doSomething(emailGet, usernameGet).


The 4th and 5th parameters for JsonObjectRequest are in fact objects of types Response.Listener and Response.ErrorListener. These two listeners are Single Abstract Method interfaces. If expanded it would look like this:

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()
        }
    }
)

The lambda syntax you were using was a short hand of SAM interfaces.

Sign up to request clarification or add additional context in comments.

Comments

2

The simplest way is using @ttyip's answer but you could also use live data and observing it! You're calling an asynchronous method and there's going to be some delay(network API calling and this delay depends on user's internet connection etc) So First you'll need to add jetPack's lifeCycle components inside your project:

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"
}

After syncing your project, define global inside your activity/fragment:

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

And inside your response:

 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()
        }
    )

And somewhere inside your activity just observe your livedata:

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

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.