I'm currently developping an android app which is accessing to an online API. I have a class dedicated to this task, and another class that just use the informations retrieved from the API. The problem is that when I call the API access class, it has to be asynchronous (defined by android studio) so I use a new Thread, but the return in the class that use the data is null, when the API access class return the good result.

I already tried to join the two threads with thread.join() but it doesn't work.

Here is the function that access the API in the API access class.The System.out at the end works as expected (I see the good result in the console)

Thread t = new Thread() {
            public void run() {
                try {
                    String url = "-----------------------------------------------"+id;
                    URL obj = new URL(url);
                    HttpURLConnection con = (HttpURLConnection) obj.openConnection();

                    con.setRequestMethod("GET");

                    con.setRequestProperty("x-api-key", "-------------------------------");
                    int responseCode = con.getResponseCode();

                    BufferedReader in = new BufferedReader(new InputStreamReader(con.getInputStream()));
                    String inputLine;
                    StringBuffer response = new StringBuffer();

                    while ((inputLine = in.readLine()) != null) {
                        response.append(inputLine);
                    }
                    in.close();
                    HttpRequest.retour = new JSONArray(response.toString());
                    System.out.println(HttpRequest.retour.toString());
                }catch(Exception e){
                    e.printStackTrace();
                }
            }
        };
        t.start();

But when I try to do that in another class :

System.out.println(retour.toString());

I get a null pointer exception because the return of the previous method is null.

What's my mistake here?

2 Answers

3
Vringar On Best Solutions

This is probably because you have a data race. When you have to threads they execute in parallel, which in this case means your main thread reaches the System.out.println(retour.toString()); before your networking thread writes the response to the object.
You'll have to find a way to synchronize them to ensure this doesn't happen.
Seeing as you are on Android you might want to take a look at retrograde and OkHttp to abstract this low-level functionality away.

2
Community On

Well, if you are using separate thread for the API call you can't expect it to be finished when you call retour.toString(). It's also a bad idea to store async operation result in static field as it wouldn't work in multi-threaded environment. You can try Completable future:

public CompletableFuture<String> callApi() {
    CompletableFuture<String> completableFuture  = new CompletableFuture<>();
    Executors.newCachedThreadPool().submit(() -> {
        // your api call
        completableFuture.complete(apiResult);
        return null;
    });
    return completableFuture;
}

//in other thread call future synchronously
String result = completableFuture.get();