retrofit for android - how to do sequential network calls - android

in my android app i have 3 network calls and they are dependent on the call before it. So 1 must finish, then 2 can go and finally 3 gets run with the data from the previous ones. So i need the network calls to run sequentially is the goal. after one call is finished it will have data passed to the next call, etc. I dont want to use rxJava. Is there a way with retrofit to make this happen ? My project is already using retrofit thus i want to continue using it ? I've tried playing around with asynchTask but its not clean and since im using retrofit i thought i would ask.

If you're using Retrofit with the asynchronous Callbacks then for the first network call you can pass in the generated interface which represents the web service that you're interacting with. In the success method you can then use the instance of the generated interface to make a second network call, using the data which came back in success under the parametrised type T, and so on for the third call inside a second callback. For example:
class FirstCallback implements Callback<First> {
private Api api;
public FirstCallback(Api api) {
this.api = api;
}
void success(First data, Response response) {
api.secondCall(data, new SecondCallback(api))
}
}
// somewhere else in your code
api.firstCall(new FirstCallback(api));
This is a quick solution using chaining with the asynchronous calls. This would most likely look more sequential and easier to read inside of an AsyncTask using the synchronous calls, which would return the type T directly. For example:
class MyTask extends AsyncTask<Void, Void, Void> {
protected Void doInBackground(Void... params) {
First first = api.firstCall();
Second second = api.secondCall(first);
// ...and so on until you return the final result
}
}

Related

How to make multiple calls with Retrofit?

I need to make multiple calls to API REST with Retrofit and show the response in a ListView, but I don't know how to do this and this code doesn't work.
Model
#GET("apks/{sha256}")
Call<DatoAPI> getTask2(#Path("sha256") String hash, #Query("Authorization") String key);
Implementation
for (String s: hash) {
Call<DatoAPI> call = services.getTask2(s, API.API_KEY);
call.enqueue(new Callback<DatoAPI>() {
#Override
public void onResponse(Call<DatoAPI> call, Response<DatoAPI> response) {
if (response.isSuccessful()) {
datoAPI = response.body();
items.add(datoAPI.getApp());
}
}
#Override
public void onFailure(Call<DatoAPI> call, Throwable t) {
Toast.makeText(getApplicationContext(),t.getMessage(),Toast.LENGTH_LONG).show();
}
});
}
Also I tried with call.execute() and same problem
I want to show this response in a ListView but it doesn't work.
First of all you need to understand the differences between Retrofit's Call#enqueue() and Call#execute() methods.
enqueue() method is Asynchronous which means you can move on to another task before it finishes
execute() method is Synchronous which means, you wait for it to finish before moving on to another task.
And in your case, you're using for loop to execute multiple requests in a single stretch.
Now, if you use for loops to execute network operation, the network operation will not stop for loops from going to the next iteration. Do not expect that the API will always respond in a fast enough way before going to for loops next iteration. That's a bad idea.
If you use Retrofit's execute() method, it will not allow you to continue to next line (or iteration) as its Synchronous behavior, plus it throws NetworkOnMainThreadException and IOException. Hence, you need to wrap the request in an AsyncTask and handle IOException.
I'd recommend you to use RxAndroid with RxJava instead of using for loops. There are plenty of tutorials out there on this topic.
Refer to the following StackOverflow questions to solve your problem.
How to make multiple request and wait until data is come from all the requests in Retrofit 2.0 - Android?
Asynchronous vs synchronous execution, what does it really mean?
Adjust the code as per your requirements.
Good luck!

How to continue with Rest calls if the first one satisfies the condition?

I'm switching from plain Retrofit to RXJava because I have to make multiple REST calls. But I'm having trouble understanding how to do the following:
First I would like to call an endpoint that returns data validity and if new data has to be fetched I have to get the new data from 5 other endpoints. After all data is retrieved and saved I have to continue to a new Activity.
I know how to make one call, but I have no idea how to do the above. Tips or links to tutorials would be greatly appreciated.
Try the following simple approach that I use in my applications: use Events
In your build.gradle module-level file:
compile 'org.greenrobot:eventbus:3.0.0'
Then, simply create a POJO class that represents your event like this:
public class DataValidationEvent{
private boolean isDataValid;
public DataValidationEvent(boolean isValid){
this.isDataValid = isValid;
}
public boolean isDataValid(){
return isDataValid;
}
}
Then, in your HTTP Request when you have received the response stating whether the data is valid (from that endpoint), notify some class or activity to do the next operation like make the expected request. Like this:
if(responseIsValid){
EventBus.getDefault().post(new DataValidationEvent(true));
}else{
EventBus.getDefault().post(new DataValidationEvent(false));
}
//obviously, you can simplify the above code to a one-liner
//by passing the actual variable returned
Next, in the activity that you need to trigger other http requests/operations, do this:
#Override public void onStart(){
super.onStart();
EventBus.getDefault().register(this);
}
#Override public void onStop(){
super.onStop();
EventBus.getDefault().unregister(this);
}
Then finally, within the same activity that you registered for events above, you need to handle (subscribe) to the event like this:
#Subscribe
public void onValidResponse(DataValidationEvent event){
//here you can call the next api request or start activity.
}
I know this might not do everything you want to do but should guide you towards an Event-driven solution that decouples your project using the popular publisher/subscriber design pattern!
Good luck and I hope this helps!
The quick-and-dirty functional solution, assuming apiClient is a retrofit client, and cacheData saves and returns the cached data object:
Observable<Data> dataObs =
apiClient
.isDataValid()
.filter(data -> !data.isValid)
.flatMap(oldData -> Observable.zip(
apiClient.fetchA(),
apiClient.fetchB(),
apiClient.fetchC(),
apiClient.fetchD(),
apiClient.fetchE(),
(a,b,c,d,e) -> cacheData(a,b,c,d,e))
.switchIfEmpty(Observable.defer(() -> getFromCache()));
Keep in mind that this will make a call to the API each time it's subscribed to; you may want to limit the frequency of such calls.

Start Android activity when receiving the last response from multiple Volley requests

In the OnCreate method of my splashscreen, I make 2 different Volley requests :
RequestQueue queue = AppController.getInstance().getRequestQueue();
GsonRequest<WPPosts> myReq = new GsonRequest<WPPosts>(urlJson, WPPosts.class, null,createMyReqSuccessListener(),createMyReqErrorListener());
queue.add(myReq);
and another one to get the categories.
I would like to start my MainActivity when I receive the last response from these 2 resquests :
private Response.Listener<WPPosts> createMyReqSuccessListener() {
return new Response.Listener<WPPosts>() {
#Override
public void onResponse(WPPosts response) {...}
Regardless response arrives first or last.
Would it be a semaphorical approach ?
Just create a class which extends Response.Listener. This class should also contain a static variable count. When you receive a callback onResponse() increment the count by 1.
When count is 2 launch the MainActivity.
Please use the same instance of the class for both the volley requests your are making.
You don't need to extend listeners or anything like that.
You can just set in your splashscreen a static int, which you increment in onResponse of these requests. onResponse is delivered in the main thread so you don't need to worry about threading issues here.
Note that you probably want to have this value incemented onError as well as if an error occurs you will be never able to go to the main activity :)

Where to attach the reference to a Retrofit adapter in Android?

I am referencing this post Where to keep Retrofit Adapter in Android App? but I am not allowed to comment there due to stackoverflow limitations [thank you stackoverflow for treating new users like kids].
Where does the Retrofit RestAdpater go when using Android? Can anybody please elaborate on #Jake Wharton 's answer of above post.
When I place the RestAdapter in my Activity, it will probably get GCed when the Activity is destroyed, so the Singleton loses its reference and needs to be recreated the next time (I assume).
Further, the first thing that I did for testing is exactly this and Android tells me I cannot do a network request on the Main thread. I understand that I can't do that, but I thought Retrofit would automatically create a separate thread for me.
Will I need to create an AsyncTask to host the RestAdapter? Or how exactly does this work for Android? Where is the adapter best instantiated? Which is the recommended point to attach the Retrofit reference?
So what #JakeWharton was saying is that the RestAdapter and the api interface instances should be created once. How you achieve that is pretty much an implementation details.
In a straight forward manner you could create a class which would hold a single instance to your RestAdapter. You would be responsible of making only a single instance of that class. You'd probably want to hold a reference to this class in your Application class. You could also approach this using the Singleton pattern
Here's a small class to get you started. I took this from a previous post which you can see here
public class RestApiDispencer {
private Map<String, Object> restApiInstances = new HashMap<String, Object>();
private RestAdapter restAdapter;
public RestApiDispencer(RestAdapter restAdapter) {
this.restAdapter = restAdapter;
}
public <T> T getRestApi(Class<T> clazz) {
T client = null;
if ((client = (T) restApiInstances.get(clazz.getCanonicalName())) != null) {
return client;
}
client = restAdapter.create(clazz);
restApiInstances.put(clazz.getCanonicalName(), client);
return client;
}
}
If you're familiar with dependency injection then that would be another way to go. Personally I prefer to use dependency injection when it comes to hiding implementation details from use.
Creating the RestAdapter directly into your Activity would not the way you'd want to go. Instead in your activity would want to get a reference to this RestApiDispencer class from above and have it return the instance of the rest api of your choise by providing its class like so.
MyClassApi myClassApi = restApiDispencer.getRestApi(MyClassApi.class);
There are other ways to achieve this but as I said it's up to you to decide which implementation fits best your needs.
As for Retrofit doing request on a separate thread, yes it does but you need to create your Api interfaces accordingly.
#GET(/some/rest/api/path)
Response getApiData() // Synchronous declaration as the Response is returned from the method.
#GET(/some/rest/api/path)
void getApiData(Callback<Response> callback); // Asynchronous as the Response is delivered in the callback.
#GET(/some/rest/api/path)
Observable<Response> getApiData(); // Asynchronous again but you'll need to read up on rx-java before using this.
Read on rx-java here
So if you do decide to create your rest api by using the asynchronous signature then you won't have to worry about threading when invoking your interface. If you use the synchronous signature then it's all up to you.

Blocking/Synchronous function call in AIDL

I am working on a android service, this service provided a AIDL interface for applications, Now application calls function GetData() using AIDL interface, this function is implemented in Service , it does some network operation, connect to server and fetch some data, this network transaction happen in background thread, Problem is that I want function GetData() should NOT return until network operation is complete, result comes from server and I want to return it into GetData(), GetData function returns immediately and network operation in background thread keep on running in parallel, how to avoid this, cannot call network operation also in main thread. I read about countDownlatch, is it only possible solution?
Service Main Thread
GetData
GetDataFromServer-----------> in Background thread
/*this is problem */ GetData returns; |
|
|
communication in progress
|
|
|
/*I want GetData should return here <-------------------transaction complete
Create some interface and implement that interface in your class and pass the interface object to that particular service after response came from the network pass the data to that interface object.
i think this help you.
you can call startService from AsyncTask.I can have the same problem in my nearest place application that need data from google map.enter code here
protected void getLocationAndUpdatePlaces(boolean updateWhenLocationChanges) {
// This isn't directly affecting the UI, so put it on a worker thread.
AsyncTask<Void, Void, Void> findLastLocationTask = new AsyncTask<Void, Void, Void>() {
#Override
protected Void doInBackground(Void... params) {
// Find the last known location, specifying a required accuracy of within the min distance between updates
// and a required latency of the minimum time required between updates.
// start a service that require data from web.
}
};
findLastLocationTask.execute();
`

Categories

Resources