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 :)
Related
I have an ObservableBoolean as follows:
public final ObservableBoolean searching = new ObservableBoolean(false);
I then have a method to perform an HTTP request:
public void search() {
searching.set(true);
// Perform HTTP request, then on Result:
searching.set(false);
}
I have a view bound to "searching" which triggers a custom BindingAdapter method, passing in the value of searching.
The above works well when there is a pause between searching.set(true) and searching.set(false), as is the case when an asyncronous HTTP request is made. I get two callbacks to my BindingAdapter method as expected, one true, and one false.
Problem arises when I cache the search results and the HTTP request is no longer required. In this case, there is no pause between searching.set(true) and searching.set(false), like so:
public void search() {
searching.set(true);
searching.set(false);
}
With this code I only get the false callback to my BindingAdapter method. What happened to the true callback? Why is it getting dropped? Is there a way to prevent it from getting dropped?
This is working as designed. Android data binding sets all values in a posted message, so only one last set call is made. This is intended to be a performance improvement among other things.
If you want to ensure the call is made inline, you can force evaluation of bindings:
public void search() {
searching.set(true);
binding.executePendingBindings();
searching.set(false);
}
This assumes that search() is executed on the UI thread. If it isn't, you'll have to post it because executePendingBindings() must be run on the UI thread.
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.
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
}
}
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.
I read a post about Volley and I know it's great networking library. But I couldn't understand one thing.
All requests are Async Task or not?
When I want to send asyncTask request using Volley do I need put Volley request in AsyncTask?
or should I just call Volley Request if it is already AsyncTask request?
private class MyClass extends AsyncTask<String, Void, String> {
#Override
protected String doInBackground(String... params) {
// do Volley request
}
}
Is this right approach?
You don't need to run Volley request on AsyncTask.
Why:
They manage all network related task on separate thread.
If you look closely at library project they did not picture the AsyncTask.
But they intelligently handle all network related task efficiently.
Check RequestQueue.java class in Volley's main package
here I am pasting java doc.
/**
* A request dispatch queue with a thread pool of dispatchers.
*
* Calling {#link #add(Request)} will enqueue the given Request for dispatch,
* resolving from either cache or network on a worker thread, and then delivering
* a parsed response on the main thread.
*/
Edited:
Forming a Request:
With Volley, network communication is managed by the RequestQueue. The best way to utilize the RequestQueue and all of its tools, especially the cache, is by instantiating it once and keeping it around as a singleton. At this point you can then add or cancel requests, stop or start requests, and access the response cache(s).
RequestQueue queue =Volley.newRequestQueue(this);
Once the RequestQueue has been instantiated a request must be formed. This can be done utilizing a few different “out of the box” request classes included with the Volley Library or by extending Volley’s request class into your own custom request. The request classes already included in Volley are a String request, JSON requests, and an Image Request. Most of the request classes included in Volley library utilize constructors much like the one below.
Parameters being passed into constructor:
RequestMethod(get, post, delete, ect)
JSONObject-An optional object that will be posted with your request
ResponseListener- Where your data will go after the request is complete
ErrorListener – What will be told when there was a problem with your request.
JsonObjectRequest request = JsonObjectRequest(Requestmethod, url, null, new ResponseListener(), new ErrorListener());
Listners to receive response:
Successful Response Listener
private class ResponseListener implements Response.Listener{
#Override
public void onResponse(JSONObject response){
}
}
Error Response Listener
private class ErrorListener implements Response.ErrorListener{
#Override
public void onErrorResponse(VolleyError error){
}
}
Finally add your request to Request queue, rest of everything Volley will handle for you.
Making call:
Now, that we have made our request and response classes we are ready to add the request to the queue and retrieve the data. To do so we simply add the request to the queue.
queue.add(request);
The response or error will then be delivered to the response/error classes that we defined in our request. You can add as many requests to the queue that you would like at one time and the responses will be delivered to their respective response/error classes
When you use Volley, there's no need to combine it with AsyncTask. It does the networking stuff on another thread for you.
Here is a basic example of a network call using Volley. As you can see, all the code is just in the Activity, without any need to define an AsyncTask.
Volley cannot be inserted inside AsyncTask because,
Volley is initiating background thread(s) on its own so all the network requests are executed off the UI thread so primarily you don't need to extend AsyncTask anymore. Of course you will have to take care to cancel the running requests on rotation or when user exits your activity..
As Volley is mainly used for minor Networking purposes in Android (for major use DownloadManager). It does similar working of AsyncTask Class. Implement Singleton in Volley.
Images can also be sent in Volley.
The whole point of introducing Volley library was to make sure user doesnt have to worry about all the "obvious" stuff while sending a network request. This means that volley takes care of the following on its own
Switching Background thread
Transparent disk and memory response
Multiple concurrent network connections. etc
To answer your question- You don't need to worry about switching to background thread, Volley takes care of this on its own. Also once the request is completed the success or failure callback is invoked on the main thread.Hence with Volley developer need not worry about switching threads
This tutorial here gives a good step by step explanation of Working with Volley Library