7

I'm using google volley for networking in android. I will make a http GET request and need to return a response header value. I found some answers on stack overflow to access the header fields, but don't know how to return it to my calling spot. Please have a look at my code, I put four numbers in it to explain my problem.

At (1) I can print out the value which I need. Than I've tried to save it in a class attribute (2) and there is no error in the IDE. If I want to return it from there (3), I got a NullPointerException at (4). Maybe its a read before write problem there. So how can I get the value from (1) to (4)? Thanks a lot!

public class Login {

String phpsessid = null;

public Login() {}

public String getSessionId(Context context) {
    RequestQueue queue = Volley.newRequestQueue(context);
    StringRequest sr = new StringRequest(Request.Method.GET, "any url",
            new Response.Listener<String>() {
                @Override
                public void onResponse(String response) {
                    System.out.println(response);
                }
            }, new Response.ErrorListener() {
                @Override
                public void onErrorResponse(VolleyError error) {
                }
            }) {
        @Override
        protected Response<String> parseNetworkResponse(NetworkResponse response) {
            System.out.println(response.headers.get("Set-Cookie")); (1)
            phpsessid = response.headers.get("Set-Cookie"); (2)
            return super.parseNetworkResponse(response);
        }
    };
    queue.add(sr);
    return phpsessid; (3)
}

}

in main:

Login login = new Login();
String result = login.getSessionId(this.getContext);
System.out.println(result);  (4)
Danny Archer
  • 215
  • 4
  • 12

1 Answers1

9

When you add a request to the queue, that request is executed asynchronously. This means it is not executed in the same order as you're reading it - it happens on another thread, and will return eventually when it's done.

protected Response<String> parseNetworkResponse(NetworkResponse response) {
    System.out.println(response.headers.get("Set-Cookie")); (1)
    phpsessid = response.headers.get("Set-Cookie"); (2)
    return super.parseNetworkResponse(response);
}

This returns the body of the response - from what I'm reading in your code, it looks like you want to return the value of the "Set-Cookie" header. You can do this like this:

protected Response<String> parseNetworkResponse(NetworkResponse networkResponse) {
    String sessionId = response.headers.get("Set-Cookie");
    com.android.volley.Response<String> result = com.android.volley.Response.success(sessionId,
            HttpHeaderParser.parseCacheHeaders(networkResponse));
    return result;
}

This will return the value of the "Set-Cookie" header to your onResponse method:

new Response.Listener<String>() {
    @Override
    public void onResponse(String response) {
        System.out.println(response);
    }
}

A better idea may be to pass a success/failure listener in when making your getSessionId call. In this way, you can then easily get access to the result in the calling class:

public void getSessionId(Context context, final Response.Listener<String> successListener, Response.ErrorListener failureListener) {
    RequestQueue queue = Volley.newRequestQueue(context); // This should be a singleton!
    StringRequest sr = new StringRequest(Request.Method.GET, "any url",
            successListener, 
            failureListener) {
        @Override
        protected Response<String> parseNetworkResponse(NetworkResponse networkResponse) {
            String sessionId = response.headers.get("Set-Cookie");
            com.android.volley.Response<String> result = com.android.volley.Response.success(sessionId,
                    HttpHeaderParser.parseCacheHeaders(networkResponse));
            return result;
        }
    };
    queue.add(sr);
}

Edit:

Now, you can call this as follows:

Login login = new Login();
login.getSessionId(this, new Response.Listener<String>() {
                @Override
                public void onResponse(String response) {
                    // You can access member variables from here.
                    // This will only get called after the network activity has happened!
                    phpsessid = response;
                    // All the work you need to do after your session ID has updated, you can put into a method and call it from here
                    // In your original example, this would be (4)
                    onSessionIdUpdated();
                }
            }, new Response.ErrorListener() {
                @Override
                public void onErrorResponse(VolleyError error) {
                    // We'll just ignore these for now - you should handle errors though!
                }
            });
// Anything you put here will happen immediately after the getSessionId call above, and notably *before* onResponse or onErrorResponse is called (ignoring potential race conditions here for now).
Adam S
  • 16,144
  • 6
  • 54
  • 81
  • Thank you very much. But I still have problems with accessing the sessionId in the calling class. I've created there the isteners and passed them as parameters. But than I can't access the response String inside the onResponse() method from the calling class. Could you please show me how to do it right in the calling class? Thx – Danny Archer Mar 03 '14 at 03:15
  • You cannot access it immediately; you have to handle the result in a callback once the network request returns. Without additional description of what problems you're having, I can't really help further. – Adam S Mar 03 '14 at 03:17
  • Yes I was typing and posted the unfinished comment by mistake, sorry. Edited it again with more infos. – Danny Archer Mar 03 '14 at 03:20
  • What _do_ you get in the `onResponse(String response)` method? Have you put a breakpoint in? If you've set it up so that you're passing the listeners in as parameters that's great; you'd be getting compile errors if it wasn't going to work. – Adam S Mar 03 '14 at 03:23
  • i've tried to put the response in the class variable like before, but with the difference that its now in the class where I need the sessionid. But the same error because of nullpointerException. I'm not familar with such breakpoint usage, do I need to check if the response is ready? Thought thats the task of the listener. Sorry, first time for me working with such a problem case. – Danny Archer Mar 03 '14 at 03:29
  • No problem. I've added some code to demonstrate how to use your `Login` class in the way described. – Adam S Mar 03 '14 at 06:25
  • Worked for me, Excellent – ManishSB Sep 19 '15 at 06:25