Save asynchronous retrofit response - android

I am using retrofit:2.1.0 and I am trying to save the response returned to my own POJO (UserProfile) but I can't seem to access the POJO, I assign the response to, outside of the callbacks.
So, in this call below, I want to have access to UserProfile outside of this call.
//adding `UserProfile userProfile;` outside of Call didn't help either
call.enqueue(new Callback<UserProfile>() {
#Override
public void onResponse(Call<UserProfile> call, Response<UserProfile> response) {
if (response.isSuccessful()) {
UserProfile userProfile = response.body();
}
}
#Override
public void onFailure(Call<UserProfile> call, Throwable t) {
//do something
}
});
//here userProfile is null and hence can't get status
Log.d(TAG, "Status outside of Call is: " + userProfile.getStatus());
New approach, same result
private List<UserProfile> userProfileList = new ArrayList<>();
call.enqueue(new Callback<UserProfile>() {
#Override
public void onResponse(Call<UserProfile> call, Response<UserProfile> response) {
if (response.isSuccessful()) {
UserProfile userProfile = response.body();
userProfileList.add(userProfile);
}
}
#Override
public void onFailure(Call<UserProfile> call, Throwable t) {
//do something
}
});
And this one gets fired even before callback and hence is null
if(userProfileList.size() > 0) {
for(UserProfile userProfile : userProfileList) {
Log.d(TAG, "Status is: " + userProfile.getStatus());
}
} else {
Log.d(TAG, "YakkerProfileList is NULL");
}

I added a setter in onResponse() which allowed me to use the response object elsewhere in the code like so:
#Override
public void onResponse(Call<UserProfile> call, Response<UserProfile> response) {
if (response.isSuccessful()) {
UserProfile userProfile = response.body();
//elsewhere in the code, I can read the value from this method
setUserProfile(userProfile.getStatus());
}
}

Related

The retrofit API call is initiated after i try to display the results

I'm using the MVVM architecture, i have my model class "Category" and my ViewModel class and the MainActivity and Adapter for Recyclerview ,
All is works fine if i set the adapter inside the activity (inside onResponse methode of the Retrofit Call), but if i do it this way im not respecting the separation of the MVVM architecture,
here is the methode that use to excute the call :
public List<Category> getcategories() {
RestInterface restInterface = rest.getInterfaceService();
Call<List<Category>> productService = restInterface.getCategories();
productService.enqueue(new Callback<List<Category>>() {
#Override
public void onResponse(Call<List<Category>> call, Response<List<Category>> response) {
if (response.body() == null){
Log.e(TAG, "responce Call response is null ");
}else{
Log.e(TAG, "repo : "+response.body().toString());
categories = (ArrayList<Category>) response.body();
}
}
#Override
public void onFailure(Call<List<Category>> call, Throwable t) {
Log.e(TAG, "Call Fail : " + t.getMessage());
}
});
Log.e(TAG, "repo 2: "+categories.toString());
return categories;
}
here is the logcat results :
07-11 20:18:34.325 24369-24369/com.instadom E/DataRepository: repo 2: []
07-11 20:18:35.399 24369-24369/com.instadom E/DataRepository: repo : [exemple.com.models.Category#1df175e, exemple.com.models.Category#5cfc73f, exemple.com.models.Category#1e7380c, exemple.com.models.Category#7ceb555, exemple.com.models.Category#3014b6a, exemple.com.models.Category#a83985b, exemple.com.models.Category#3d5c8f8, exemple.com.models.Category#d1251d1]
what i can't understand is why i don't get any result in the "Log.e(TAG, "repo 2: "+categories.toString());" even tho "categories" is a class object
I would apreciate any help,
thanks in advance,
Here is the code :
public List getcategories(final Callback>
callback) {
RestInterface restInterface = rest.getInterfaceService();
Call> productService = restInterface.getCategories();
productService.enqueue(new retrofit2.Callback>() {
#Override
public void onResponse(Call> call, Response> response) {
if (response.body() == null){
Log.e(TAG, "responce Call response is null ");
}else{
Log.e(TAG, "repo : "+response.body().toString());
categories = (ArrayList) response.body();
callback.onSuccess(categories);
}
}
#Override
public void onFailure(Call<List<Category>> call, Throwable t) {
Log.e(TAG, "Call Fail : " + t.getMessage());
callback.onFailure(t.getMessage());
}
});
Log.e(TAG, "result : "+categories.toString());
return categories;
}
public interface Callback<T> {
void onSuccess(ArrayList<Category> data);
void onFailure(String reason);
}
here is the error :
java.lang.NullPointerException: Attempt to invoke interface method 'void instadom.com.repositories.DataRepository$Callback.onSuccess(java.util.ArrayList)' on a null object reference
That is because productService.enqueue is an asynchronous call, The statement Log.e(TAG, "repo 2: "+categories.toString()); will be executed right after the call is is enqued and the onResponse or onFailure will be executed after a network call. pass in a callback to the getCategories() to get the category list like this
public interface Callback<List<Categories>> callback{
void onSuccess(List<Categories> data);
void onFailure(String reason);
}
or you can use a generic callback interface to use in all your network requests like this
public interface Callback<T> callback{
void onSuccess(List<T> data);
void onFailure(String reason);
}
then implement the callback functionality
public List<Category> getcategories(Callback<List<Category>> callback) {
RestInterface restInterface = rest.getInterfaceService();
Call<List<Category>> productService = restInterface.getCategories();
productService.enqueue(new Callback<List<Category>>() {
#Override
public void onResponse(Call<List<Category>> call, Response<List<Category>> response) {
if (response.body() == null){
Log.e(TAG, "responce Call response is null ");
}else{
Log.e(TAG, "repo : "+response.body().toString());
categories = (ArrayList<Category>) response.body();
callback.onSuccess(categories);
}
}
#Override
public void onFailure(Call<List<Category>> call, Throwable t) {
Log.e(TAG, "Call Fail : " + t.getMessage());
callback.onError(t.getMessage());
}
});
}

Am I using LiveData properly in this code? (works)

I'm new to Android development, and am trying to use a good pattern for accessing my data from a web service using ViewModel, Retrofit, LiveData. Looking for feedback on this pattern.
I went through a few iterations and online guides, and came up with this
From the Activity:
LiveData<TicklerResponse> ticklerLiveData =
ticklerViewModel.search(ticklerSearchObject);
ticklerLiveData.observe(this, new Observer<TicklerResponse>() {
#Override
public void onChanged(#Nullable TicklerResponse ticklerResponse) {
Log.d(TAG, "onChanged: ticklerResponse size = " + ticklerResponse.getContent().size());
}
});
The ViewModel
public LiveData<TicklerResponse> search(TicklerSearchObject ticklerSearchObject) {
TicklerRepository ticklerRepository = TicklerRepository.getInstance();
String header = OscarOAuthContainer.getInstance()
.generateAuthorizationHeader(Verb.POST,"/tickler/search?startIndex=0&limit=1000");
MutableLiveData<TicklerResponse> liveData = new MutableLiveData<TicklerResponse>();
ticklerRepository.search(header,liveData, ticklerSearchObject);
return liveData;
}
The Repository
public void search(final String authHeader, final MutableLiveData<TicklerResponse> ticklerLiveData, TicklerSearchObject ticklerSearchObj) {
Log.d(TAG, "search: called");
Call<TicklerResponse> call = api.search(authHeader,0,1000,ticklerSearchObj);
call.enqueue(new Callback<TicklerResponse>() {
#Override
public void onResponse(Call<TicklerResponse> call, Response<TicklerResponse> response) {
if(response.isSuccessful()){
Log.d(TAG, "onResponse: successful response for getProvider");
TicklerResponse result = response.body();
ticklerLiveData.setValue(result);
} else {
Log.d(TAG, "onResponse: NOT SUCCESSFUL");
}
}
#Override
public void onFailure(Call<TicklerResponse> call, Throwable t) {
t.printStackTrace();
}
});
}
It seems to work, but I'm concerned if I'm using the LiveData structure correctly in how it's being instantiated/passed around.

Retrofit response showing

I tried to post raw data to server using retrofit method, but I receive the failure response like res fail: Response{protocol=http/1.1, code=500, message=Internal Server Error, url=http://192.168.1.9:8000/api/deviceinfo}
apiService = RetrofitSingleton.createService(ApiService.class);
spyApp = new SpyApp();
Call<ModelResponse> call = apiService.eventsUpdate(jsonObj);
call.enqueue(new Callback<ModelResponse>() {
#Override
public void onResponse(Call<ModelResponse> call, Response<ModelResponse> response) {
Log.e("response", new Gson().toJson(response.body())); //This shows null
if (response.isSuccessful()) {
String status = response.body().getData().getStatus();
} else {
Log.e("res fail", response.toString());
}
}
#Override
public void onFailure(Call<ModelResponse> call, Throwable t) {
Log.e("failure",t.getMessage());
}
});

Retrofit return boolean value

I want to run changesHasBeenSaved if saveChanges function gives me true value.
How can I get boolean or string or integer, any value, when Retrofit finish?
Is it possible?
I need a function similar this:
public boolean saveChanges()
{
Boolean output = false;
RequestAPI requestAPI = Requests.getRetrofit();
Call<Object> jsonObjectCall = requestAPI.readAllCategoeies();
jsonObjectCall.enqueue(new Callback<Object>() {
#Override
public void onResponse(Call<Object> call, Response<Object> response) {
if(response.body() != null) {
output = true;
}
}
#Override
public void onFailure(Call<Object> call, Throwable t) {
call.cancel();
}
});
return output;
}
You should change method return type boolean to void as retrofit work asynchronous.
You should pass the listener/callback to get the status in callback.
First create callback interface like below
public interface ApiCallback {
void onResponse(boolean success);
}
Here how saveChanges will look like
public void saveChanges(final ApiCallback callback)
{
RequestAPI requestAPI = Requests.getRetrofit();
Call<Object> jsonObjectCall = requestAPI.readAllCategoeies();
jsonObjectCall.enqueue(new Callback<Object>() {
#Override
public void onResponse(Call<Object> call, Response<Object> response) {
callback.onResponse(response.body() != null);
}
#Override
public void onFailure(Call<Object> call, Throwable t) {
call.cancel();
callback.onResponse(false);
}
});
}
Then you need to call saveChanges method like below
saveChanges(new ApiCallback () {
public void onResponse(boolean success){
if(success){
// do something
} else{
// do something
}
}
});
jsonObjectCall.enqueue(new Callback<Object>() {
#Override
public void onResponse(Call<Object> call, Response<Object> response) {
//when the response is successful
if(response.isSuccessful()) {
output = true;
// display response as string
Log.i(TAG, "post submitted to API." + response.body().toString());
//Object user1 = response.body(); maps response to the modal class
}
}
#Override
public void onFailure(Call<Object> call, Throwable t) {
call.cancel();
}
})
Change you call back to like the above , included comments for clearity about usage .
Hope this helps.

Android:Retrofit: Multiple consecutive async requests. Тoo many nested items

com.squareup.retrofit2:retrofit:2.3.0
My steps:
Start async request: getCompaniesList()
Wait success response
Start another async request: getCatalogsList()
Wait success response
Do some another code
Here snippet in my activity:
RestClient restClient = RestClientFactory.getRestClient();
Call<List<Company>> companyList = restClient.getCompaniesList(filters);
companyList.enqueue(new Callback<List<Company>>() {
#Override
public void onResponse(Call<List<Company>> call, Response<List<Company>> response) {
if (response.isSuccessful()) {
RestClient restClient = RestClientFactory.getRestClient();
Call<List<Catalog>> catalogList = restClient.getCatalogsList(filters);
catalogList.enqueue(new Callback<List<Catalog>>() {
#Override
public void onResponse(Call<List<Catalog>> call, Response<List<Catalog>> response) {
if (response.isSuccessful()) {
// HERE SOME NEED CODE!!!
}
}
#Override
public void onFailure(Call<List<Catalog>> call, Throwable throwable) {
}
});
}
}
#Override
public void onFailure(Call<List<Company>> call, Throwable throwable) {
}
});
I think this structure is not very nice. Тoo many nested items. As result code is more complicated.
Question: Has any alternative to this structure?
You can either take time to learn Rx RXjava2
or you can split up your code like this
RestClient restClient = RestClientFactory.getRestClient();
Call<List<Company>> companyList = restClient.getCompaniesList(filters);
companyList.enqueue(getCompanyListCallback());
private Callback<List<Company>> getCompanyListCallback() {
return new Callback<List<Company>>() {
#Override
public void onResponse(Call<List<Company>> call, Response<List<Company>> response) {
if (response.isSuccessful()) {
RestClient restClient = RestClientFactory.getRestClient();
Call<List<Catalog>> catalogList = restClient.getCatalogsList(filters);
catalogList.enqueue(getCatalogsListCallback());
}
}
#Override
public void onFailure(Call<List<Company>> call, Throwable throwable) {
}
};
}
private Callback<List<Catalog>> getCatalogsListCallback() {
return new Callback<List<Catalog>>() {
#Override
public void onResponse(Call<List<Catalog>> call, Response<List<Catalog>> response) {
if (response.isSuccessful()) {
// HERE SOME NEED CODE!!!
}
}
#Override
public void onFailure(Call<List<Catalog>> call, Throwable throwable) {
}
};
}

Categories

Resources