0
votes

I am studying Kotlin programming for Android and I am trying to understand this code (that works) deeply. It comes from the Volley library for network request:

//Network stuff
    // Request a string response from the provided URL.
    val jsonObjectRequest = object : JsonObjectRequest(Method.POST, http, ob,
            Response.Listener<JSONObject> { response ->
                // Display the first 500 characters of the response string.
                Log.d("Debug","Response is: ${response.toString()} ")

            },
            Response.ErrorListener { error ->
                Log.d("Debug","That didn't work! Code: ${error.message}")
            })
    {
        @Throws(AuthFailureError::class)
            override fun getHeaders(): Map<String, String> {
                val headers = HashMap<String, String>()
                headers.put("Content-Type", "application/json")
                headers.put("Accept", "application/json")
                return headers
        }

    }

My question is about the first block, right inside the constructor of the JsonObjectRequest object. I know the object construct, lambdas, classes, and interfaces but there is one little thing that I don't get here. Moreover, I have already seen this thread Pass interface as parameter in Kotlin.

My question is: what is happening in the fourth parameter used to construct the JsonObjectRequest? From what I see, there is a lambda overriding some function related to Response.Listener<JSONObject> but I don't find any reference to this syntax.

To conclude, the objectRequest has the former constructor:

    public JsonObjectRequest(int method, String url, JSONObject jsonRequest,
        Listener<JSONObject> listener, ErrorListener errorListener) {
    super(method, url, (jsonRequest == null) ? null : jsonRequest.toString(), listener,
                errorListener);
}

and the listener has the following section:

public class Response<T> {

/** Callback interface for delivering parsed responses. */
public interface Listener<T> {
    /** Called when a response is received. */
    void onResponse(T response);
}

/** Callback interface for delivering error responses. */
public interface ErrorListener {
    /**
     * Callback method that an error has been occurred with the
     * provided error code and optional user-readable message.
     */
    void onErrorResponse(VolleyError error);
}

Reading this I get that with this syntax we are implementing the Listener interface but I don't get why we use a lambda, since in the Listener there is no reference to it, and in particular what does this mean:

 Response.Listener<JSONObject> { response ->
            // Display the first 500 characters of the response string.
            Log.d("Debug","Response is: ${response.toString()} ")

        }

Anyone willing to explain this or pointing to some references related to this syntax?

1

1 Answers

2
votes

This is a SAM-conversion. Because Response.Listener<JSONObject> is a SAM-interface (has a single method without a default implementation) and defined in Java, you can write

Response.Listener<JSONObject> /* lambda */

and the lambda is used as the implementation of the method. I.e. it's equivalent to

object : Response.Listener<JSONObject> {
    override fun onResponse(response: JSONObject) {
        Log.d("Debug","Response is: ${response.toString()} ")
    }
}