I have some troubles trying to execute this code:
#Override
public void loginProcessGoogle(User googleUser) {
Retrofit retrofit = new Retrofit.Builder()
.baseUrl(Constants.BASE_URL)
.callbackExecutor(Executors.newSingleThreadExecutor())
.addConverterFactory(GsonConverterFactory.create())
.build();
RequestInterface requestInterface = retrofit.create(RequestInterface.class);
User user = new User();
String email = googleUser.getEmail() == null ? "" : googleUser.getEmail();
String name = googleUser.getName();
String googleId = googleUser.getProvider_id();
user.setEmail(email);
user.setName(name);
user.setProvider_id(googleId);
user.setProvider_name(User.provider_name_google);
ServerRequest request = new ServerRequest();
request.setUser(user);
Call<ServerResponse> response = requestInterface.socialAuthenticate(request);
response.enqueue(new Callback<ServerResponse>() {
#Override
public void onResponse(Call<ServerResponse> call, retrofit2.Response<ServerResponse> response) {
ServerResponse resp = response.body();
Snackbar.make(getView(), resp.getMessage(), Snackbar.LENGTH_LONG).show();
if(resp.getResult().equals(Constants.SUCCESS)){
SharedPreferences.Editor editor = pref.edit();
editor.putBoolean(Constants.IS_LOGGED_IN,true);
editor.putString(Constants.EMAIL,resp.getUser().getEmail());
editor.putString(Constants.NAME,resp.getUser().getName());
editor.putString(Constants.ID,resp.getUser().getId());
editor.apply();
goToProfile();
}
progress.setVisibility(View.INVISIBLE);
}
#Override
public void onFailure(Call<ServerResponse> call, Throwable t) {
progress.setVisibility(View.INVISIBLE);
Log.d(Constants.TAG,"failed");
Snackbar.make(getView(), t.getLocalizedMessage(), Snackbar.LENGTH_LONG).show();
}
});
String testString= "Hello";
}
When im debuggin this code, i put a breakpoint for example in user.setEmail(email);,it enters, also with another before the response.enqueue callback, when im trying to put a breakpoint inside onResponse method, it goes immediately to the string variable in the bottom (testString)
What is the best way to enter first into the response.enqueue before the string variable in the bottom, for example in ServerResponse resp = response.body();?
You cannot, because the enqueue method run in another thread with the thread you setEmail, untill retrofit receive the result it execute onResponse method.
Yo can use excute method instead enque. See here for more details https://futurestud.io/tutorials/retrofit-synchronous-and-asynchronous-requests.
Related
I am learning Retrofit in android.
I am calling a Retrofit API inside a String method which returns a String. Generally calling the method it is returning the default value not the API response value.
I needed to wait till getting API response then assign to String variable and then return that value. How to do that? Anyone can help me please? Thanks in advance.
public String checkIsSubscribe(String video_user_id) {
final String[] is_subscribed = {"false"};
APIService apiService = RetrofitInstance.getRetrofitInstance().create(APIService.class);
Call<String> call = apiService.checkIfSubscribed(video_user_id, "2");
call.enqueue(new Callback<String>() {
#Override
public void onResponse(Call<String> call, Response<String> response) {
if (response.code() == 200 ){
String result = response.body();
Log.e("checkIfSub result = ", result);
if (result == "true"){
is_subscribed[0] = "true";
Log.e("checkIfSub innner = ", is_subscribed[0]);
}
}else{
}
}
#Override
public void onFailure(Call<String> call, Throwable t) {
}
});
return is_subscribed[0];
}
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.
I switched to Kotlin along the way, so this may not be correct Java, but it shows the process
Set the user model as LiveData
update the user model using .postValue()
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
}
}
}
Im in a confusing spot right now. My API returns a Token for Login when posting a new User with UserData. How do I get the response.body() as a String to save it?
It only returns a Post object what I don't actually want. I only use it to create the Post.
private void createPost(User user) {
Post post = new Post(user.getName(), user.getGender(), user.getBirthyear(), user.getHeight(),user.getWeight());
Call<Post> call = jsonmongo.createPost(post);
// To execute it asynchron
call.enqueue(new Callback<Post>() {
#Override
public void onResponse(Call<Post> call, Response<Post> response) {
if (!response.isSuccessful()) {
Log.e("RESPONSECODE", ""+ response.code());
return;
}
Log.e("RESPONSECODE", ""+ response.code());
}
#Override
public void onFailure(Call<Post> call, Throwable t) {
Log.e("RESPONSECODE", ""+ t.getMessage());
}
});
}
Get Response.Body and save it to the Database via SQL Adapter ( adapter.addToken(response.body()) )
response.body().toString only returns Object reference ( com.example.Resources.Post#4c8352 )
String S = new Gson().toJson(response.body())
Log.e("JSON", S)
Returns this:
E/JSON: {"age":0,"gender":0,"height":0,"weight":0}
Wanted output:
E/JSON: {"token":aslfjkhr9RRRRf283FGr3489pjfGGG34HH89fj}
let me try... you can use Gson library to create a String json object from the response.
Try it:
new Gson().toJson(response);
So I have this POST request made to the server and based on an argument the server will return error message within the errorBody() of Retrofit. I am trying to handle that Plain Text error returned by the server and then display it to the user within my Android application which uses Java. Below is my current attempt but this is giving me this error in Logcat:
#Url cannot be used with #POST URL (parameter #1)
Here is 400 response from the server:
Interface:
public interface ChangePickLocationClient
{
#GET
Call<ResponseBody> checkItem(#Url String url, #Header("Authorization") String authToken);
#GET
Call<String> getStringError(#Url String url, #Header("Authorization") String authToken);
#POST("Pick/ChangePickLocationAcceptChange")
Call<String> changePickLocationPOST(#Url String url, #Header("Authorization") String authToken, #Body
ChangePickLocationPostModel changePickLocationPostModel);
}
Implementation:
private static final String BASE_URL = "http://00.00.00.1234/api/";
Gson mGson = new Gson();
Retrofit retrofit = new Retrofit.Builder().client(new OkHttpClient())
.baseUrl(BASE_URL).addConverterFactory(ScalarsConverterFactory.create())
.addConverterFactory(GsonConverterFactory.create(mGson))
.build();
ChangePickLocationClient ChangePickLocationClient =
retrofitPOST.create(ChangePickLocationClient.class);
String itemNumber = itemNumberValue.getText().toString();
newPickLocationValue.setText(newPickLocationValue.getText().toString().toUpperCase());
String newPickLocation = newPickLocationValue.getText().toString();
String token = globalClass.getActiveToken();
final ChangePickLocationClient mChangePickLocationInterface =
retrofit.create(ChangePickLocationClient.class);
Call<String> mCallErrorPOST = mChangePickLocationInterface.changePickLocationPOST
(postUrl, "Bearer " + globalClass.getActiveToken(),
changePickLocationPostModel);
call.enqueue(new Callback<ChangePickLocationPostModel>()
{
#Override
public void onResponse(Call<ChangePickLocationPostModel> call,
Response<ChangePickLocationPostModel> response)
{
String mPlainTextResponse = null;
try {
if(response.errorBody() != null)
{
mPlainTextResponse = response.errorBody().string();
}
} catch (IOException e)
{
e.printStackTrace();
}
Toast.makeText(ChangePickLocation.this, mPlainTextResponse
,Toast.LENGTH_SHORT).show();
}
#Override
public void onFailure(Call<ChangePickLocationPostModel> call, Throwable t)
{
Toast.makeText(ChangePickLocation.this, "Unknown server error!"
,Toast.LENGTH_SHORT).show();
}
});
When the response is 400, the second call being made needs to be a clone() call. This is because the Call cannot be used more than once as stated in the documentation.
use this:
call.clone().enqueue(new Callback<ChangePickLocationPostModel>()
instead of
call.enqueue(new Callback<ChangePickLocationPostModel>()
This project run with a web server. When user click button, it should post the message inside of EditText. I use Retrofit2 for it. The program has stoped when I click button.
ApiInterface.java
#POST("api/EmergencyNotification/SendNotification")
Call<SendMessageModel>postMessage(#Header("Authorization") String token,
// #Field(("PhotoRequest")) String photoRequest,
// #Field(("Location")) String location,
#Field(("MessageBody")) String messageBody);
// #Field(("AnswerValue")) String answerValue);
In the button OnClick this function runs:
protected void postMessage(){
startProgress();
String authorization = SessionHelper.getCustomerTokenWithBearer();
// Loc = lattitude + longitude;
Call<SendMessageModel> call = ApiService.apiInterface.postMessage(authorization,
mesaj.getText().toString().trim());
call.enqueue(new Callback<SendMessageModel>() {
#Override
public void onResponse(Call<SendMessageModel> call, Response<SendMessageModel> response) {
stopProgress();
if (response.isSuccessful()){
if (response.body() != null){
DialogHelper.showDialogWithOneButton("",response.body().getData());
}
}
else {
ApiErrorUtils.parseError(response);
}
}
#Override
public void onFailure(Call<SendMessageModel> call, Throwable t) {
stopProgress();
DialogHelper.showFailedDialog();
}
});
}
Ok. I solved it now. My api url was wrong and I added new #Multipart and #Part instead of #Field.
#POST("api/EmergencyNotification/SendMessage")
Call<SendMessageModel>postMessage(#Header("Authorization") String token,
#Part(("MessageBody")) String messageBody);
You are missing #FormUrlEncoded attribute since you are using field attribute instead of body
#POST("api/EmergencyNotification/SendNotification")
#FormUrlEncoded
Call<SendMessageModel>postMessage(#Header("Authorization") String token,
...