AlfaLaurens
AlfaLaurens

Reputation: 41

Return variable from onResponse Retrofit

I do a API call to a webserver and I get the ID back in the method onResponse.

Now I want to save this ID and return this id in the return of the method doLogin. How can I get that variable ID in the return statement?

This is my code:

public class LoginController {

    public static String doLogin(String loginMail, String loginPassword) {

        //Logging Retrofit
        final HttpLoggingInterceptor interceptor = new HttpLoggingInterceptor();
        interceptor.setLevel(HttpLoggingInterceptor.Level.BODY);
        OkHttpClient client = new OkHttpClient.Builder().addInterceptor(interceptor).build();

        Retrofit retrofit = new Retrofit.Builder()
                .baseUrl("###URLTOAPICALL###")
                .client(client)
                .addConverterFactory(GsonConverterFactory.create())
                .build();

        APIService service = retrofit.create(APIService.class);
        Call<JsonElement> call = service.doLogin(loginMail, loginPassword);

        call.enqueue(new Callback<JsonElement>() {
            @Override
            public void onResponse(Call<JsonElement> call, Response<JsonElement> response) {

                if (response != null) {
                    JSONObject obj = null;

                    try {
                        obj = new JSONObject(response.body().toString());
                    } catch (JSONException e) {
                        e.printStackTrace();
                    }

                    JSONObject setup = null;
                    try {
                        setup = obj.getJSONObject("setup");
                    } catch (JSONException e) {
                        e.printStackTrace();
                    }

                    if(setup != null) {
                        try {
                            Setup stp = new Setup();
                            stp.setUserId(setup.getInt("id"));

                            //I WANT HERE TO SAVE MY ID

                        } catch (JSONException e) {
                            e.printStackTrace();
                        }


                    }
                }
            }

            @Override
            public void onFailure(Call<JsonElement> call, Throwable t) {
                Log.v("ERROR", t+"");
            }


        });

        return "I WANT RETURN THAT ID HERE";
    }
}

Upvotes: 2

Views: 7415

Answers (4)

Enock Lubowa
Enock Lubowa

Reputation: 717

You can use a setter method within the onResponse method of your Retrofit call. Take an instance where I have a global variable to hold distance between two points that I get from the Google maps distance matrix API:

String final_distance;

Here's my retrofit call:

call.enqueue(new Callback<JsonObject>() {
        
        @Override
        public void onResponse(Call<JsonObject> call, Response<JsonObject> response) {
            // TODO Auto-generated method stub
            JsonObject object = response.body();
            String distance = object.get("rows").getAsJsonArray().get(0).getAsJsonObject().get("elements").getAsJsonArray().
                    get(0).getAsJsonObject().get("distance").getAsJsonObject().get("value").getAsString();
            //The setter method to change the global variable
            setDistance(distance);

        }
        
        @Override
        public void onFailure(Call<JsonObject> call, Throwable t) {
            // TODO Auto-generated method stub
            
        }
    });

This is what the setter method does:

private static void setDistance(String distance) {
    final_distance = distance;
}

Since the Retrofit onResponse method is asynchronous, you will need to always first check whether the final_distance is not null before using it

Upvotes: 3

Arlind Hajdari
Arlind Hajdari

Reputation: 485

While call.execute() function is synchronous it triggers app crashes on Android 4.0 or newer and you'll get NetworkOnMainThreadException. You have to do an async request initializing your global variable into a runnable thread. At your class name add Runnable implementation.Your getDataFunction() will look something like this:

public void getData(){
    Call<JsonElement> call = service.doLogin(loginMail, loginPassword);

    call.enqueue(new Callback<JsonElement>() {
        @Override
        public void onResponse(Call<JsonElement> call, Response<JsonElement> response) {

            if (response.isSuccessful() && response != null) {
                jsonObject = response.body().toString();//initialize your global variable
            }
        }

        @Override
        public void onFailure(Call<JsonElement> call, Throwable t) {
            Log.v("ERROR", t+"");
        }
    });

}

@Override
pulic void run(){
    getDataFunction();
    //here you can use your initialized variable
}

Now on your onCreate function create the run thread and start it.

Thread thread = new Thread(this);
thread.start();

This is the way it solved a similar problem of mine.

Upvotes: 1

Emanuel
Emanuel

Reputation: 8106

You can't since the Call you are requesting is async. If you want to run it in the same thread you must avoid using enqueue and use execute(). Keep in mind that you need to create a thread since you cant use Network Operations on the same thread.

You can solve it using Observables or use execute like in this case (not tested)

 public static String doLogin(String loginMail, String loginPassword) {

            //Logging Retrofit
            final HttpLoggingInterceptor interceptor = new HttpLoggingInterceptor();
            interceptor.setLevel(HttpLoggingInterceptor.Level.BODY);
            OkHttpClient client = new OkHttpClient.Builder().addInterceptor(interceptor).build();

            Retrofit retrofit = new Retrofit.Builder()
                    .baseUrl("###URLTOAPICALL###")
                    .client(client)
                    .addConverterFactory(GsonConverterFactory.create())
                    .build();

            APIService service = retrofit.create(APIService.class);
            Call<JsonElement> call = service.doLogin(loginMail, loginPassword);

            try {
                Response response = call.execute();
                if (response.isSuccessful()) {

                    // do your stuff and 

                    return yourString;

                }
            }catch (IOException ex) {
                ex.printStackTrace();
            }
} 

You can call it in your activity using

    new Thread(new Runnable() {
        @Override
        public void run() {
            String var = doLogin("email", "paswsord");
        }
    }); 

Take care that if you want to update your UI you need to use

runOnUiThread();

Upvotes: 0

Pratik Popat
Pratik Popat

Reputation: 3009

As retrofit is asynchronous don't return from method instead use interface callbacks.

public class LoginController {

    public interface LoginCallbacks{
        void onLogin(String id);
        void onLoginFailed(Throwable error);
    }

    public static void doLogin(String loginMail, String loginPassword, final LoginCallbacks loginCallbacks) {

        //Logging Retrofit
        final HttpLoggingInterceptor interceptor = new HttpLoggingInterceptor();
        interceptor.setLevel(HttpLoggingInterceptor.Level.BODY);
        OkHttpClient client = new OkHttpClient.Builder().addInterceptor(interceptor).build();

        Retrofit retrofit = new Retrofit.Builder()
                .baseUrl("###URLTOAPICALL###")
                .client(client)
                .addConverterFactory(GsonConverterFactory.create())
                .build();

        APIService service = retrofit.create(APIService.class);
        Call<JsonElement> call = service.doLogin(loginMail, loginPassword);

        call.enqueue(new Callback<JsonElement>() {
            @Override
            public void onResponse(Call<JsonElement> call, Response<JsonElement> response) {

                if (response != null) {
                    JSONObject obj = null;

                    try {
                        obj = new JSONObject(response.body().toString());
                    } catch (JSONException e) {
                        e.printStackTrace();
                    }

                    JSONObject setup = null;
                    try {
                        setup = obj.getJSONObject("setup");
                    } catch (JSONException e) {
                        e.printStackTrace();
                    }

                    if(setup != null) {
                        try {
                            Setup stp = new Setup();
                            stp.setUserId(setup.getInt("id"));

                            //I WANT HERE TO SAVE MY ID
                            if (loginCallbacks != null)
                                loginCallbacks.onLogin(setup.getInt("id"));
                        } catch (JSONException e) {
                            e.printStackTrace();
                        }


                    }
                }
            }

            @Override
            public void onFailure(Call<JsonElement> call, Throwable t) {
                Log.v("ERROR", t+"");
                if (loginCallbacks != null)
                    loginCallbacks.onLoginFailed(t);
            }


        });
    }
}

Call method:

doLogin("email", "password", new LoginCallbacks() {
            @Override
            public void onLogin(String id) {

            }

            @Override
            public void onLoginFailed(Throwable error) {

            }
        });

Upvotes: 6

Related Questions