I'm using Volley in Android in order to make requests including fetching relatively large amount of data. I want to make timer of 5 seconds and if after it the request not returned - it probably means that there is slow connection and therefore I want to cancel the request. So far what I did:
Timer timer = new Timer();
VioozerVolleyRequestFactory mFactory = new VioozerVolleyRequestFactory(this);
RequestQueue mQueue = VioozerVolleySingleton.getInstance(this).getRequestQueue();
timer.schedule(new TimerTask() {
#Override
public void run() {
mQueue.cancelAll("MY_TAG");
}
}, 5000};
Request<String> request = mFactory.createRequest(RequestType,
new Listener<String>() {
#Override
public void onResponse(String response) {
timer.cancel();
//...
}
},
new ErrorListener<String>() {
#Override
public void onErrorResponse(String response) {
timer.cancel();
//...
}
}, extra);
request.setTag("MY_TAG");
mQueue.add(request);
My question: It seems that the request not canceled. The request is executed so the build in method cancelALL(TAG) not relevant here. How can I still achieve my requirement?
Thanks,
By default Volley request timeout is set to 2500ms and it makes 1 retry per request.
You need to override DefaultRetryPolicy of Request.
for example:
Wait for 5000ms and do not perform any retry.
request.setRetryPolicy(new DefaultRetryPolicy(5000,0,1f));
Ref: DefaultRetryPolicy.java
Related
I know there are multiple post on doing this, but with limited Android experience I am little confused as to who to believe. I have an app that loads content on start up from my server thru Volley request. After a period of time I want to make a Volley request back to update the content that is displayed to the user. When the app first loads, I determine the number of seconds from the half hour which I pass to the following
public static void refreshAllContent(final long timetoupdate) {
new CountDownTimer(timetoupdate, 1000) {
public void onTick(long millisUntilFinished) {
}
public void onFinish() {
Log.i("SCROLLS ", "UPDATE CONTENT HERE ");
resetContent();
}
}.start();
}
On the finish it calls the refreshAllContent which is where I would make the Volley request and reset the count for the next update, I have something like
public static void resetContent(){
Handler handler= new Handler();
Runnable runnable= new Runnable() {
#Override
public void run() {
//PUT VOLLEY REQUEST HERE
refreshAllContent(Times. initialTime());
}
};
}
I guess I am stuck as to exactly how to make the Volley request, meaning what do I have to worry do this. Like I said not a lot of experience so not sure if I run the request in a special runnable or task. Any direction appreciated.
EDIT: I reworked this some, instead of going back to the refreshAllContent, I replaced this with
private static void resetContent(){
Log.i("SCROLLS ", "ENTER resetContent");
final Handler handler= new Handler();
Runnable runnableCode = new Runnable() {
#Override
public void run() {
refreshData(); // Volley Request
handler.postDelayed(runnableCode, 20000);
}
};
handler.post(runnableCode);
}
Logic is now on the initial run, the first timetoupdate is created and passed to the refreshAllContent. Once the countdown is complete, the resetContent() will run which makes the Volley Request in the refreshData(). Now I am getting an error stating the runnableCode needs to be declared final since it's accessed from an inner class, same for the handler. Well adding final to the
final Runnable runnableCode=new Runnable(){
line doesn't fix the error, I still have an error telling me the runnableCode has not been initialized. Can I get little help on this.
You don't create a Runnable to run Volly. Volly runs network calls on a background thread by default.
Here is a simple Volly code:
public void volleyProcess(){
RequestQueue requestQueue = Volley.newRequestQueue(this);
StringRequest request = new StringRequest(Request.Method.GET, "https://api.myjson.com/bins/753rt", new Response.Listener<String>() {
#Override
public void onResponse(String response) {
Log.d(TAG, response);
refreshAllContent(30000);
}
}, new Response.ErrorListener() {
#Override
public void onErrorResponse(VolleyError error) {
Log.d(TAG, error.toString());
}
});
requestQueue.add(request);
}
onResponse() is called when a response is successfully returned by the call. This method is called on the main thread therefore you can run your refreshAllContent() method here. and the parameter 'response' is the data returned, do what ever you want with it here(i am simply printing it to the Logcat).
Now to make this code run after the desired interval, just call it in onFinish() of the countdownTimer.
public static void refreshAllContent(final long timetoupdate) {
new CountDownTimer(timetoupdate, 1000) {
public void onTick(long millisUntilFinished) {
}
public void onFinish() {
Log.i("SCROLLS ", "UPDATE CONTENT HERE ");
volleyProcess();
}
}.start();
}
Hope this helped
I have a Forgot Password screen. The user fills in his email, clicks on submit and an HTML request is submitted. It either returns the string "true" or "false". If it returns true, I would change the text on the screen, wait for 2 seconds and send the user to another page. Here's how I'm doing it
StringRequest stringRequest = new StringRequest(Request.Method.GET, url, new Response.Listener<String>() {
#Override
public void onResponse(String response) {
if ("true".equals(response)) {
//make one TextView invisible and the other visible.
findViewById(R.id.pre_password_reset_text).setVisibility(View.INVISIBLE)
findViewById(R.id.post_password_reset_text).setVisibility(View.VISIBLE);
try {
Thread.sleep(2000);
} catch (InterruptedException e) {
e.printStackTrace;
}
startActivity(new Intent(ForgotPassword.this, Login.class));
} else {
//show error message
}
}
}, new Response.ErrorListener() {
#Override
public void onErrorResponse(VolleyError error) {
//show error message
}
});
requestQueue.add(stringRequest);
The problem is, the thread goes to sleep for 2 seconds and after that the text-change happens. But, in the code I've written the text-change to happen first and then Thread.sleep.
What am I missing here?
Using Volley, the onResponse() code is called from the main thread, so calling Thread.sleep is definitelly forbidden because it would block the UI.
If you want to delay the call to the next activity, you need to defer it to a runnable, and delay it :
#Override
public void onResponse(String response) {
if ("true".equals(response)) {
//make one TextView invisible and the other visible.
TextView passwordView = (TextView) findViewById(R.id.pre_password_reset_text).setVisibility(View.INVISIBLE);
findViewById(R.id.post_password_reset_text).setVisibility(View.VISIBLE);
passwordView.postDelayed(new Runnable() {
public void run() {
startActivity(new Intent(ForgotPassword.this, Login.class));
}
}, 2000);
} else {
//show error message
}
}
A cleaner way would be to create a Handler in your Activity/Fragment and post the runnable on it, but it is simpler to directly use your password view.
Thread.sleep in main thread of your app isn't a good idea. You could use Android handlers to schedule a task in the future. Handlers will behave in an asynchronous message passing manner, so you don't freeze up your whole app during the wait period.
handler.postDelayed(new Runnable(){
#Override
public void run(){
// Start your new activity here!
}
}, 2000);
Note: All views and their derivations come with a built-in handler, so you wouldn't need to define a bare handler for this purpose.
I have a Retrofit network call that id like to run every 5 seconds. My current code:
Handler h = new Handler();
int delay = 5000; //milliseconds
h.postDelayed(new Runnable() {
public void run() {
call.enqueue(new Callback<ApiResponse>() {
#Override
public void onResponse(Response<ApiResponse> response) {
Log.d("api", "response: " + response.body().getPosition().getLatitude().toString());
}
#Override
public void onFailure(Throwable t) {
}
});
h.postDelayed(this, delay);
}
}, delay);
This runs once, but then throws the following:
java.lang.IllegalStateException: Already executed.
at retrofit2.OkHttpCall.enqueue(OkHttpCall.java:52)
at retrofit2.ExecutorCallAdapterFactory$ExecutorCallbackCall.enqueue(ExecutorCallAdapterFactory.java:57)
at orbyt.project.MyFragment$1.run(MyFragment.java:93)
Whats the issue here?
As a bonus: whats a better way to handle this? Ill be updating a map every update. I was thinking about trying to use Rx but not sure if this is an appropriate use-case, or how to implement it.
A Call can only be used once. Its documentation tells you how to use one multiple times:
Use clone() to make multiple calls with the same parameters to the same webserver; this may be used to implement polling or to retry a failed call.
So use call.clone().enqueue(..) for Asynchornous and call.clone().execute() for Synchornous respectively to ensure that you have a fresh, unexecuted Call for each request.
I'm using Volley for Android. I have a ListView in a fragment. If this ListView is empty (only possible if the connection failed/no internet/etc.), I want to send a GET request to the server for the data, then populate the ListView accordingly if it succeeds. If the call failed, I want to call it again in 5 minutes. This goes on until it succeeds.
What is the best way to achieve this? I'm new to Android development. I read about Services, but IDK if that is overkill.
You could use ScheduledExecutorService to manage and schedule your request.
Take a look at:
http://tutorials.jenkov.com/java-util-concurrent/scheduledexecutorservice.html
http://developer.android.com/reference/java/util/concurrent/ScheduledExecutorService.html
I use to have a layer to define all my calls to services. Lets say ServiceLayer.java for example.
You could define a Handler as a global variable. (You will need to create the ServiceLayer in the MainThread). And then manage the error in the service call making the handler recall the service in 5 minutes. Something like this
public class ServiceLayer {
Handler handler = new Handler();
...
public void callToService(final String parameter,final String moreParameters,final Callback callbackDefinedByYou){
StringRequest req = new StringRequest(Method.GET, url, new Response.Listener<String>(){
#Override
public void onResponse(String s) {
//Do whatever you need, populate listviews etc
callbackDefinedByYou.populateListView(s);
}
}, new Response.ErrorListener() {
#Override
public void onErrorResponse(VolleyError volleyError) {
//Manage the error and recall again this service
callbackDefinedByYou.onError(volleyError);
handler.postDelayed(new Runnable() {
public void run(){
callToService(parameter, moreParameter, callbackDefinedByYou);
}
}, 300000); //5 minutes
}
});
VolleyHelper.addRequestToQueue(req);
}
In this code, everytime service fails a recall is made but, in some cases you should stop doing net calls. For example when you detect there is no internet conexion, and let the user refresh screen
I am implementing one app related to alaram manager and brodcastreceivers.
I am repeting alarm in every minute,through the alarm manager I call brodcastresever class.
In side this class I am implementing one thread. The code is as follows:
runnable = new Runnable()
{
public void run()
{
while(i>o)
{
}
}
if i>o the thread will continue.
Another time my alaram manager call brodcast resever class. That time also one new thread is created with old thread. This increases duplication of threads.
How to avoid that?
Why not you use a queue of requests to process instead of creating new thread every time. Like:
if(queue==null)
{
queue= new ArrayList<Request>();
queue.add(request);
start();
}
public void run()
{
while(queue!=null && queue.size()>0)
{
Request request= fetchRequest();
processRequest(request);
}
}
private Request fetchRequest()
{
Request request=queue.get(0);
queue.remove(0);
if(queue.size()==0)
queue=null;
return request;
}
Note its just a prototype, not implementation.