I've searched all over but haven't found an answer to this.
In my Android application, the user can use the app offline, and some events generate http GET requests to my server. I am using Volley, and when the user is online the requests work properly, but offline they fail immediately and are removed from the request queue.
I wanted Volley to store these requests, and try again when the server is accessible, or at least keep trying. Is this behaviour possible?
Here's how I'm doing things:
StringRequest request = new StringRequest(Request.Method.GET, url, listener, listener);
request.setRetryPolicy(new DefaultRetryPolicy(8000, 2, 1.5f));
postToDefaultQueue(request);
private void postToDefaultQueue (StringRequest request) {
if (sQueue == null) {
sQueue = Volley.newRequestQueue(mContext.get());
}
sQueue.add(request);
}
Thanks so much, any help appreciated
Edit
So I managed to make the request go back to the queue after it fails. The code is below:
private class DummyListener implements Response.Listener<String>, Response.ErrorListener {
String mUrl;
public DummyListener (String url){
mUrl = url;
}
#Override
public void onErrorResponse(final VolleyError error) {
new Timer().schedule(new TimerTask() {
#Override
public void run() {
Log.v(DummyListener.class.getSimpleName(), "ErrorResponse", error);
offlineStringGetRequest(mUrl);
}
}, 5000);
}
#Override
public void onResponse(String response) {
Log.d(DummyListener.class.getSimpleName(), "Response: " + response);
}
}
The problem that remains is that if I kill the app, the queue gets destroyed, and the request is never made.
Edit2
Noticed some people liked this question. I ended up using Path (https://github.com/path/android-priority-jobqueue) with some modifications for the job. It worked perfectly. Just wish Volley had a native way for doing this
Since I found no way to do this with Volley, I ended up using Path
And it worked wonders
Related
My Android application needs to do an initial http request on app start to fetch a config json file from a RESTful service. This request is done by Volley
As soon as the application gets the data, the MainActivity starts. I also defined some deeplinks, to open a WebView in my application with a given URI. The deeplinks have to be handled by the SplashActivity as the config needs to be loaded first by Volley. I don't know if this is the right way to handle this.
Maybe it would be an option to request the config in the Application class, so that the config is always available, no matter which Activity starts first?
This is the correct way.
In your Splash activity you should handle the incoming intent with your deeplinks, fire up your Volley request and only then you should move on with your logic.
BTW, in the meanwhile, you should show the user some loader/progress and handle failures of course.
If you are making an asynchronous call in the Application class, you can make the request with a callback and show the required activity.
public interface ConfigListener {
public void onConfigReceived(List<ofSomething> list, boolean error, String message);
}
private void requestConfig(){
final DownloadUsingVolley downloader = new DownloadUsingVolley(getActivity());
downloader.retrieveData(new ConfigListener() {
#Override
public void onConfigReceived(List<ofSomething> list, boolean error, String message) {
//Show your required activity here
}
});
}
private void retrieveData(String url, final ConfigListener configListener){
final JsonObjectRequest request = new JsonObjectRequest(url, null, new Response.Listener<JSONObject>(){
#Override
public void onResponse(JSONObject response) {
try {
//parse
configListener.onConfigReceived(result,false,null);
}catch (JSONException e){
configListener.onConfigReceived(0,true,e.getMessage());
}
}
},new Response.ErrorListener(){
#Override
public void onErrorResponse(VolleyError volleyError) {
configListener.onConfigReceived(0,true,volleyError.getMessage());
}
});
//adding request into the queue
ApplicationClass.getInstance().addToRequestQueue(request,"aTag");
}
Before I get the obligatory "you shouldn't be testing real network responses for XYZ reasons!", it should be noted that I am not asking whether or not I should.
I am asking specifically how I would go about doing so, if I wanted to.
After a few hours of struggle I've successfully managed a proper response from Volley, and have that test going.
The problem I'm having now, is that call.enque(...) seems to hang on the RobolectricTestRunner. Unlike Volley, I can't peek in and see whats going on in there (for Volley, the challenge was not realizing that Looper.getMainLooper doesn't get properly created.)
So, all I am doing is trying to make a simple request to the server via Retrofit. The issue, as I said, is that the entire system hangs at call.enqueue, and there is no error or response ever (even when my await is longer). The network call works fine with volley, but I am getting this snag here with Retrofit. Here's the code if you want to try it. And of course, the function works fine when the app is running.
//in NetworkManager.class
public void someCall(HashMap properties, NetworkResponseListener listener){
this.okHttpClient = new OkHttpClient.Builder().cache(new Cache(appContext, 35 * 1024 * 1024)).build();
this.retrofit = new Retrofit.Builder().baseUrl(httpPath + apiHost).client(okHttpClient).build();
this.myService = retrofit.create(MyService.class);
Call call = myService.someRequest(properties);
call.enqueue(new Callback<ResponseBody>() {
#Override
public void onResponse(Call<ResponseBody> call, retrofit2.Response<ResponseBody> response) {
listener.onSuccess(response);
}
#Override
public void onFailure(Call<ResponseBody> call, Throwable t) {
listener.onError(t);
}
});
}
Service:
interface MyService {
#GET("/api/SomeEndpoint/")
Call<ResponseBody> someRequest(#QueryMap Map<String, Object> params);
}
Test:
#Test
public void testSomeCall() throws Exception {
//Network class has setup OkHttpClient/Service/Retrofit already
NetworkResponseListener listener = new NetworkResponseListener() {
#Override
public void onSuccess(Response response) {
this.response = response;
}
#Override
public void onError(Throwable error) {
//
}
};
NetworkManager.someCall(this.properties, listener);
await().atMost(30, TimeUnit.SECONDS).until(ResponseReceived());
}
Everyone's response on stackoverflow has been 'don't test real network responses', which is really not helpful.
Solution is pretty much exactly the same as for volley.
Retrofit2 will default to the platform callback executor, which will not be correctly instantiated in a test.
Solution is simple. If you wish to test retrofit with real network calls, you must change the callbackExector. Here's what I ended up doing:
retrofit = new Retrofit.Builder().baseUrl(baseUrl)
.client(okHttpClient).callbackExecutor(Executors.newSingleThreadExecutor())
Network tests are running successfully.
What I want to achieve is to be able to observe changes in my web service and then update my textview if there is any change. I am currently using timer to achieve this by running it every x second. The problem though, is that the memory leaks so it's not a good solution. Now I stumbled upon this rxjava/rxjava but I'm confused on how to use it. The documentation is confusing to me and I can't find alot of tutorials about this. I am using volley to get data from my web service by the way.
this is the Observable that someone on answered on my other question but I'm getting an error which is "Incompatible types" on return sendRequest.
Observable.interval(500, TimeUnit.MILLISECONDS, Schedulers.io()).map(new Func1<Long, Object>() {
#Override
public Object call(Long tick) {
return sendRequest();
}
}).observeOn(AndroidSchedulers.mainThread()).subscribe();
here is my volley request code
public void sendRequest(){
//While the app fetched data we are displaying a progress dialog
//final ProgressDialog loading = ProgressDialog.show(this,"Fetching Data","Please wait...",false,false);
StringRequest stringRequest = new StringRequest(JSON_URL,
new Response.Listener<String>() {
#Override
public void onResponse(String response) {
//text.setText(response);
//loading.dismiss();
showJSON(response);
}
},
new Response.ErrorListener() {
#Override
public void onErrorResponse(VolleyError error) {
//Toast.makeText(MainActivity.this, error.getMessage(), Toast.LENGTH_LONG).show();
}
});
RequestQueue requestQueue = Volley.newRequestQueue(MainActivity.this);
requestQueue.add(stringRequest);
}
private void showJSON(String json){
ParseJson pj = new ParseJson(json);
pj.parseJSON();
text.setText(ParseJson.playing[0]);
}
Your method sendRequest doesn't return anything(void). You can either return null or something.
#Override
public Object call(Long tick) {
sendRequest();
return null;
}
I would suggest you firstly read Java basics instead of writing Android app.
Use push notifications to send messages from the server to the users when data is updated and avoid sending unwanted requests to the server.
Then you can send the request for new data only when notified and update the Observer someway, maybe use a rx subject, or better store the data in SQLite table and observe changes from the DB.
Recommend this to create a rx stream from sqlite
https://github.com/square/sqlbrite
GCM: https://developers.google.com/cloud-messaging/
I'm trying to use Volley to execute multiple HTTP request where each one of them relies on the result of the previous one, what is the best option as a design?
1-Firing the next request in the onResponse callback of the previous request?
2-Writing some coordinator class that have callbacks that get called in the onResponse method of a request and fires the next request
skeleton code for the second option
coodrinator = new Coordinator();
JsonObjectRequest firstRequest = new JSONObjectRequest(Request.Method.GET,firstURL),new Response.Listener<JSONObject>() {
#Override
public void onResponse(JSONObject response) {
//handle the responsee
coordinator.onFirstRequestRecieved();
}
},
errorListener);
private void doSecondRequest(){
JsonObjectRequest secondRequest = new JSONObjectRequest(Request.Method.GET,secondURL),new Response.Listener<JSONObject>() {
#Override
public void onResponse(JSONObject response) {
//handle the responsee
coordinator.onSecondRequestRecieved();
}
},
errorListener);
}
private class Coordinator{
public void onFirstReequestRecieved(){
doSecondRequest();
}
public void onSecondRequestRecieved(){
//do Something
}
}
If first request response parameters are needed for making second request and so on then you can go for synchronous way. That can be achieved by making second request in onResponse on First request can there is no good or bad practise for it.
The thing is volley is asynchronous and request what is added in the queue execute without depending on other request and we are going to make it synchronous request and it can be achieved by many ways seeing your requirement.
I've seen answer to both of these questions, however, when I tried to put them together, I couldn't make it work. The problem itself is pretty simple: I want to get a string from one site and use it in a post request. That means I can only make the post request after I've finished parsing the GET request. The main ideas I'm using are these ones:
How to return response header field to main method using Google Volley for HTTP GET request in Android / Java?
Can I do a synchronous request with volley?
However the synchronous request is blocked and doesn't go on, and the first one is Async.
I believe this to be a simple thing to do, but still, I haven't be able to do it...
Thanks for any help!
Why not do something like this:
// send first request
requestQueue.add(firstRequest, null, new Listener<JSONObject>() {
#Override
public void onResponse(JSONObject response) {
// ** code to parse response **
// send second request
requestQueue.add(secondRequest, null, new Listener<JSONObject>() {
#Override
public void onResponse(JSONObject response) {
// ** code to parse response **
}
}, new ErrorListener() {
#Override
public void onErrorResponse(VolleyError error) {
// ** code to handle errors **
}
}));
}
}, new ErrorListener() {
#Override
public void onErrorResponse(VolleyError error) {
// ** code to handle errors **
}
}));