Best way to wait for retrofit2 to finish before continuing async

HappyPoofySquirrel picture HappyPoofySquirrel · May 25, 2016 · Viewed 8.1k times · Source

I realize similar questions have been asked but I am new to android and find the answers a bit confusing since they are in a slightly different context.

I have looked at CountDownLatch aswell as using Threads and am not sure which method to use. Any help would be much appreciated. I have also tried using apply() instead of commit() for SharedPreferences.

I am making 2 retrofit2 calls from LoginActivity. I need the token from the first call to use in the second call. I am saving the token to a string in sharedpreferences in the onResponse method of the first retrofit call.

In my second call the value of serverToken is coming back as the token set in previous run of the app

1st call(getToken) onResponse

   call.enqueue(new retrofit2.Callback<TokenResponse>() {    

            @Override
            public void onResponse(Call<TokenResponse> call, retrofit2.Response<TokenResponse> response) {

                if (response.isSuccessful()) {
                    TokenResponse tokenResponse = response.body();

                    LoginActivity.editor.putString("serverToken", tokenResponse.getAccessToken());
                    LoginActivity.editor.commit();

                } else {
                    Log.i("Server Token", "failed");
                }
            }
 }

LoginActivity

public class LoginActivity extends AppCompatActivity {

    public static SharedPreferences preferences;
    public static SharedPreferences.Editor editor;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        authenticationController = new AuthenticationController();
        preferences = PreferenceManager.getDefaultSharedPreferences(this);
        editor = preferences.edit();
    }

    public void onLoginClicked(View view) {
        getToken();    //FIRST RETROFIT CALL
        connectToPush(); //SECOND CALL WHERE I NEED TOKEN FROM FIRST CALL
    }

    public void getToken() {
        authenticationController.login(grantType, username, password);
    }

    public void connectToPush() {
        authenticationController.connectToPush();
    }

My Second Retrofit call

public void connectToPush(){

  Log.i("sharedpreferencesToken", LoginActivity.preferences.getString("serverToken", "null serverToken"));

}

Answer

TommySM picture TommySM · May 26, 2016

The onResponse() method is a callback interface, which ,simply putting it, means that is where you get the info back from your request\event (you called, it came back, hence callback) and implement what you want to do with it (it's an interface, you implement it, hence the @Override annotation).

this means:

  1. You don't need CountDownLatch, at least not in this case, and Retrofit2 takes care of the threading for you.

  2. no real need for SharedPreferences, you can just call the method you want straight from that callback, since the info is in that instance (unless you want to save it for reasons other than the next request, see next...).

  3. if you want to locally store the value because you need it later (or to use as an auto-login thing later, you can use SharedPreferences, but you don't need to get your value from there in that instance - since it exists in the callback instance (your saving the value right there, it's redundant to load it from the Prefs again while the response holds the exact value that can be simply passed.

so:

call.enqueue(new retrofit2.Callback<TokenResponse>() {    

        @Override
        public void onResponse(Call<TokenResponse> call, retrofit2.Response<TokenResponse> response) {

            if (response.isSuccessful()) {
                TokenResponse tokenResponse = response.body();

                //right here you can call the other request and just give it the token
                connectToPush(tokenResponse);

                //if you really need to, save your value
                LoginActivity.editor.putString("serverToken", tokenResponse.getAccessToken());
                LoginActivity.editor.commit();

            } else {
                Log.i("Server Token", "failed");
            }
        }
 }

And in your second call:

public void connectToPush(TokenResponse tokenFromFirstRequest){

 //fire the next request using your token as a param!

}