Im making an asynchronous call and im able to send a request to the server and getting my desired JSON(using postman) but for some reason the OnResponse and OnFailure methods are not being executed, may you please help me if im missing out something.Im using retrofit2
private List<Advert> getAdverts(){
Retrofit retrofit = new Retrofit.Builder()
.baseUrl( "http://192.168.100.4:8092/portal/")
.client(client.build())
.addConverterFactory(GsonConverterFactory.create())
.build();
RequestService requestService = retrofit.create(RequestService.class);
Call<List<Advert>> customerCall= requestService.getAdverts(accountNumber);
System.out.println("++++++++++++++ request was made +++++++++++++++++++");
customerCall.enqueue(new Callback<List<Advert>>() {
#Override
public void onResponse(Call<List<Advert>> call, Response<List<Advert>> response) {
Log.d("onResponse", "" + response.message());
System.out.println("++++++++++++++ was here+++++++++++++++++++");
if (response.isSuccessful()) {
adverts.addAll(response.body());
} else {
Toast.makeText(getContext(), "" + response.message(), Toast.LENGTH_SHORT).show();
}
}
#Override
public void onFailure(Call<List<Advert>> call, Throwable t) {
Log.d("onFailure", t.toString());
}
});
return adverts;
}
Not sure, but you're returning before de operation has ended (as you mentioned is a asynchronous call). So as soon you enqueue, you're returning "adverts" (probably cancelling your call).
Consider using other alternatives to return your response, like Callbacks, EventBus, persist the response on local storage, etc.
Related
I am trying to send an io.reactivex.Flowable from a Spring RestController to an Android application that uses Retrofit and Rxjava. If I use the browser to check what the Rest endpoint returns, I get a series of values as expected but in Android I get only one value and then it calls the onComplete method. What am I missing?
Spring Controller:
#GetMapping("/api/reactive")
public Flowable<String> reactive() {
return Flowable.interval(1, TimeUnit.SECONDS).map(sequence -> "\"Flowable-" + LocalTime.now().toString() + "\"");
}
Retrofit repository:
#GET("reactive")
Flowable<String> testReactive();
Main service:
public useReactive() {
Retrofit retrofit = new Retrofit.Builder()
.baseUrl(Values.BASE_URL)
.addConverterFactory(JacksonConverterFactory.create())
.addCallAdapterFactory(RxJava2CallAdapterFactory.create())
.build();
userRepository = retrofit.create(UserRepository.class);
Flowable<String> reactive = userRepository.testReactive();
Disposable disp = reactive.subscribeOn(Schedulers.io())
.observeOn(AndroidSchedulers.mainThread())
.subscribeWith(new ResourceSubscriber<String>() {
#Override
public void onNext(String s) {
logger.log(Level.INFO, s);
Toast.makeText(authActivity, s, Toast.LENGTH_SHORT).show();
}
#Override
public void onError(Throwable t) {
t.printStackTrace();
}
#Override
public void onComplete() {
logger.log(Level.INFO, "Completed");
Toast.makeText(authActivity, "Completed", Toast.LENGTH_SHORT).show();
}
});
}
Upon calling the useReactive() method, I get only one value "Flowable-..." and then "Completed".
Even though the Retrofit service has return type Flowable<String>, calling testReactive() will only make one HTTP call on the Android device.
The type Flowable is merely for compatibility, in practice it will end up being a Flowable that emits a single value and then terminates.
This is just how Retrofit works.
You would need to find another solution if you want to continually receive new values that are being emitted from the server, perhaps GRPC or polling the server.
Imagine this scenario:
I start a requestA using the Call.enqueue() method, then, before requestA be finished, I start requestB at the same endpoint of requestA. While I'm using Call.enqueue() method, requestB will be executed after requestA? Or enqueue() method is just used to do requests asynchronously?
I search that information at docs and here on StackOverflow but all the information is superficial about this specific method.
Here is my code - this same code is used for both requests:
foolRequest.enqueue(new Callback<Response>() {
#Override
public void onResponse(#NonNull Call<Response> call,
#NonNull retrofit2.Response<Response> response) {
//do something
}
#Override
public void onFailure(#NonNull Call<Response> call,
#NonNull Throwable t) {
//do something
}
});
I think so,
Otherwise, if you implement your own connection client.
By the source code from OkHttpClient, there is a dispatcher class, save all the enqueue API, and it uses queue to save the relative task
synchronized void enqueue(AsyncCall call) {
if (runningAsyncCalls.size() < maxRequests && runningCallsForHost(call) < maxRequestsPerHost) {
runningAsyncCalls.add(call);
executorService().execute(call);
} else {
readyAsyncCalls.add(call);
}
}
I'm currently trying to use RxJava with Retrofit for the first time but can't seem to get anything working for my specific use case:
I begin by calling an API using retrofit to show cinemas near a users location.
I then use the cinema id which the user clicks on to display showtimes for this cinema i.e...
public interface ListingApiService
{
#GET("/get/times/cinema/{id}")
Call<ListingResponse> getShowtimes (#Path("id") String id);
}
Then using the interface....
public void connectAndGetApiData(String id)
{
if (retrofit == null) {
retrofit = new Retrofit.Builder()
.baseUrl(BASE_URL)
.addConverterFactory(GsonConverterFactory.create())
.build();
}
ListingApiService listingApiService = retrofit.create(ListingApiService.class);
Call<ListingResponse> call = listingApiService.getShowtimes(id);
call.enqueue(new Callback<ListingResponse>() {
#Override
public void onResponse(Call<ListingResponse> call, Response<ListingResponse> response)
{
List<Listing> listings = response.body().getListings()
getAndDisplayImage(listings.get(0).getTitle());
recyclerView.setAdapter(new ListingAdapter(listings,R.layout.list_item_listing,getApplicationContext()));
}
#Override
public void onFailure(Call<ListingResponse> call, Throwable t)
{
Log.e(TAG,t.toString());
}
});
}
I then want to call a different API (contextual web search) to display an image of a relevant movie poster (just for a nice visual effect) for each movie listing. I know how to call the API for a single image, but I don't know how to make multiple calls. I've tried using RxJava code found elsewhere on the internet but none of it seems to work as I don't have prior knowledge of how many calls I will be making or what the search term will be. The code i'm using for a single call is:
public interface ListingImageApiService
{
//https://contextualwebsearch-websearch-v1.p.mashape.com/api/Search/ImageSearchAPI?count=1&autoCorrect=false&q=Donald+Trump
#Headers("X-Mashape-Key: apikey")
#GET("/api/Search/ImageSearchAPI?count=5&autoCorrect=false")
Call<ListingImageResponse> getListingImages (#Query("q") String term);
}
public void getAndDisplayImage(String search)
{
if (retrofit2 == null)
{
retrofit2 = new Retrofit.Builder()
.baseUrl(BASE_URL2)
.addConverterFactory(GsonConverterFactory.create())
.build();
}
search = search + " poster";
ListingImageApiService listingImageApiService = retrofit2.create(ListingImageApiService.class);
Call<ListingImageResponse> call = listingImageApiService.getListingImages(search);
call.enqueue(new Callback<ListingImageResponse>() {
#Override
public void onResponse(Call<ListingImageResponse> call, Response<ListingImageResponse> response)
{
System.out.println(response.body().toString());
ListingImage a = new ListingImage();
List<ListingImage> listingImages = response.body().getListingImage();
System.out.println(listingImages.get(0).getUrl());
}
#Override
public void onFailure(Call<ListingImageResponse> call, Throwable t)
{
}
});
}
My question is, how would I use RxJava to make multiple calls using data for the list of movie titles of unknown size (which I can pass to getAndDisplayImage instead of a single string)? I have made several attempts but none seem to work for my use case. Thank you.
This design should solve your problem.
This interface contains the endpoints used in the application.
public interface ListingApiService
{
#GET("/get/times/cinema/{id}")
Observable<List<MovieResponse>> getShowtimes (#Path("id") String id);
#Headers("X-Mashape-Key: apikey")
#GET("/api/Search/ImageSearchAPI?count=5&autoCorrect=false")
Observable<ListingImageResponse> getListingImages (#Query("q") String term);
}
Method which provides the retrofit object to make the call
private API getAPI() {
Retrofit retrofit = new Retrofit.Builder()
.baseUrl("<your API endpoint address")
.addConverterFactory(GsonConverterFactory.create())
.addCallAdapterFactory(RxJava2CallAdapterFactory.create())
.build();
return retrofit.create(API.class);
}
Make the call to get the List<MovieResponse>. This method also converts the List into a individual observable MovieResponse object.
private void getMovieListingsWithImages() {
Observer<MovieResponse> observer = new Observer<MovieResponse>() {
#Override
public void onSubscribe(Disposable d) {
Toast.makeText(getApplicationContext(), "", Toast.LENGTH_SHORT).show();
}
#Override
public void onNext(MovieResponse movieResponse) {
//for each movie response make a call to the API which provides the image for the movie
}
#Override
public void onError(Throwable e) {
Toast.makeText(getApplicationContext(), "Error getting image for the movie", Toast.LENGTH_SHORT).show();
}
#Override
public void onComplete() {
Toast.makeText(getApplicationContext(), "Finished getting images for all the movies in the stream", Toast.LENGTH_SHORT).show();
}
};
getAPI().getShowtimes()
.flatMapIterable(movieResponseList -> movieResponseList) // converts your list of movieResponse into and observable which emits one movieResponse object at a time.
.flatMap(this::getObservableFromString) // method converts the each movie response object into an observable
.subscribeOn(Schedulers.io())
.observeOn(AndroidSchedulers.mainThread())
.subscribe(observer);
}
method which converts the MovieResponse object into an Observable.
private Observable<MovieResponse> getObservableFromString(MovieResponse movieResponse) {
return Observable.just(movieResponse);
}
I am implementation for Retrofit on api call using images-upload base64Encode string. it is sending data perfect but Retrofit return response Internal Server Error 500 and i am sending request type is Body custom class. Plz help me what i do.
#Headers("Accept:application/json")
#POST(RestClient.postRegister)
Call<RegisterResp> getRegisterResponse(#Body RequestRegisterVo requestRegisterVo);
Call<RegisterResp> call = MyApplication.getRestClient().getApplicationServices().getRegisterResponse(requestRegisterVo);
call.enqueue(new Callback<RegisterResp>() {
#Override
public void onResponse(Call<RegisterResp> call, Response<RegisterResp> response) {
if (Other.isValidResp(response)) {
// success Log.i(TAG,"Register successfully");
} else {
hideDialog();
}
}
#Override
public void onFailure(Call<RegisterResp> call, Throwable t) {
hideDialog();
showToast(t.getMessage());
}
});
The same issue I had to face it, I got a solution in my case-
there is parameter issue, I was sending parameters in String and at the backend, they required Integer parameters.
You also checkout may be there is the issue with parameters or second reason is the URL issue so check it URL also.
I've setup retrofit 2.1 and it is not making calls to my api at all. I just setup a lamp stack and made my ip publicly accessible. I'm trying to send information via a POST to my php script which would add data to my db. For some reason, retrofit will not make the call to my api... I'm not sure what I'm doing wrong.
#POST("/sendInformation.php")
Call<JSONObject> sendUserInfo(#Body JSONObject userViewModel);
OkHttpClient.Builder client = new OkHttpClient.Builder();
HttpLoggingInterceptor logging = new HttpLoggingInterceptor(message -> Log.d(TAG, message));
logging.setLevel(HttpLoggingInterceptor.Level.BASIC);
client.addInterceptor(logging);
Retrofit retrofit = new Retrofit.Builder()
.baseUrl(BASE_URL)
.client(client.build())
.addConverterFactory(JacksonConverterFactory.create())
.build();
UserInformationService userService = retrofit.create(UserInformationService.class);
Call<JSONObject> call = userService.sendUserInfo(jsonObject);
call.enqueue(new Callback<JSONObject>() {
#Override
public void onResponse(Call<JSONObject> call, Response<JSONObject> response) {
Toast.makeText(HomeActivity.this, response.body().toString(), Toast.LENGTH_SHORT).show();
}
#Override
public void onFailure(Call<JSONObject> call, Throwable t) {
}
});
I tried to add logging but it won't make the call so I can't even see the logging. Anyone have any ideas?
EDIT: The BASE_URL I'm using is my public IP. I just forwarded my ports so it's accessible. I tried doing a POST on hurl.it and it works fine. It's only retrofit not working. I've also tried this with an asyncTask and httpURLConnection and it also works. I must be missing something really minor...
Call<JSONObject> call = userService.sendUserInfo(jsonObject);
This line is not enough. The Call<T> object represents an 'intent' of a call rather than the operation itself, and you need to execute it by calling one of two methods on the object: execute and enqueue.
Execute works in a blocking manner and will return your JSONObject through the response.getBody() method:
Response<JSONObject> response = call.execute();
Enqueue works asynchronously and will provide your JSONObject through the callback object - if call is successful, onResponse method will be called with your response as a call parameter.
call.enqueue(new Callback<JSONObject>() {
#Override
public void onResponse(Call<JSONObject> call, Response<JSONObject> response) {
}
#Override
public void onFailure(Call<JSONObject> call, Throwable t) {
}
});