maganthro
maganthro

Reputation: 459

How can I use the Retrofit response outside the OnResponse function so I can return it up the recommended architecture model?

This question follows on from How can I use the Retrofit response outside the OnResponse function?, but I'm not allowed to comment, so I'm asking it for myself here.

I'm trying to use the Android Studio Login template because it follows the recommended architecture, but I'm having trouble returning the Result in LoginDataSource.login. The result is trapped in the Call.enqueue function and I can't get it out to return. I've reproduced the callback suggested in the above link, but that just traps the result in a new class.

How can I access the LoggedInUser returned by my server to return to my repository?

Original attempt: user is stuck in Call.enqueue - onResponse

public class LoginDataSource {
    public static Retrofit retrofit = null;
    LoggedInUser user;

    public Result<LoggedInUser> login(String username, String password) {
        user = new LoggedInUser();
        try {
            // TODO: handle loggedInUser authentication
            retrofit = new Retrofit.Builder()
                    .baseUrl("https://myserver")
                    .addConverterFactory(GsonConverterFactory.create())
                    .build();
            PostEndPoint endPoint = retrofit.create(PostEndPoint.class);
            Call<LoggedInUser> call = endPoint.getUser("login", username, password);

            call.enqueue(new Callback<LoggedInUser>() {
                @Override
                public void onResponse(Call<LoggedInUser> call, Response<LoggedInUser> response) {
                    Log.d(TAG, "onResponse: code " + response.code());
                    if (response.isSuccessful()){
                        callback.getUser();
                        user = response.body();
                        Log.d(TAG, "onResponse: " + user); // this returns valid user data
                    }
                }
            });

            Log.d(TAG, "retrofit complete:" + user.getName()); // this returns null

            return new Result.Success<>(user);
        }
    }
}

And after implementing callback: user is stuck in GetUserResponse - getUser

public class LoginDataSource {
    public static Retrofit retrofit = null;
    LoggedInUser user;

    public Result<LoggedInUser> login(String username, String password) {
        user = new LoggedInUser();
        try {
            // TODO: handle loggedInUser authentication
                retrofit = new Retrofit.Builder()
                        .baseUrl("https://myserver")
                        .addConverterFactory(GsonConverterFactory.create())
                        .build();
                PostEndPoint endPoint = retrofit.create(PostEndPoint.class);
                Call<LoggedInUser> call = endPoint.getUser("login", username, password);

                sendLoginRequest(call, new GetUserResponse(){
                    @Override
                    public void getUser(LoggedInUser userFromResponse) {
                        user = userFromResponse;
                    }
                });
                Log.d(TAG, "retrofit complete:" + user.getName()); // this returns null

            return new Result.Success<>(user);
        }
    }

    private void sendLoginRequest (Call call, final GetUserResponse callback) {
        call.enqueue(new Callback<LoggedInUser>() {
            @Override
            public void onResponse(Call<LoggedInUser> call, Response<LoggedInUser> response) {
                if (response.isSuccessful()){
                    callback.getUser(response.body());
                }
            }
        });
    }
}

public interface GetUserResponse {
    void getUser(LoggedInUser user);
}

I feel like I need to have sendLoginRequest return the user, but I can't work out how to do that. Am I heading in the right direction? Any advice is welcome.

Upvotes: 2

Views: 574

Answers (1)

maganthro
maganthro

Reputation: 459

I switched to Kotlin along the way, so this may not be correct Java, but it shows the process

  1. Set the user model as LiveData
  2. update the user model using .postValue()
  3. set up an observer for the user model in the viewmodel (not shown)
public class LoginDataSource {
    public static Retrofit retrofit = null;
    MutableLiveData<LoggedInUser> user=new MutableLiveData<>(); // changed this to LiveData so it can be observed from the viewmodel

    public Result<LoggedInUser> login(String username, String password) {
        user = new LoggedInUser();
        try {
            // TODO: handle loggedInUser authentication
            retrofit = new Retrofit.Builder()
                    .baseUrl("https://myserver")
                    .addConverterFactory(GsonConverterFactory.create())
                    .build();
            PostEndPoint endPoint = retrofit.create(PostEndPoint.class);
            loggedInUser = endPoint.getUser("login", username, password);
            user.postValue(loggedInUser); // updated the livedata here
        }
    }
}

Upvotes: 1

Related Questions