Retrofit "IllegalStateException: Already executed" - android

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.

Related

Updating Content thru Volley at Time Intervals

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

android - Starting an event with the completion of two threads running parallel

I have two or more network calls in separated threads on main activity start, I want to show all data after network threads done.
Thread firstNetworkCallThread=new Thread(new Runnable() {
#Override
public void run() {
// network calls and get data...
}
});
Thread secondNetworkCallThread =new Thread(new Runnable() {
#Override
public void run() {
// network calls and get data...
}
});
firstNetworkCallThread.start();
secondNetworkCallThread.start();
I want these threads work parallel, and when both of them are complete, call new event to show data.
How can I do this?
Guava has a good solution for this. If you convert your Threads to ListenableFutures (also a Guava object) you can create a list of ListenableFutures and add a callback to that list.
Futures.addCallback(
Futures.allAsList(/*future1*/, /*future2*/, /*future3*/),
new AbstractDisposableFutureCallback<List<Object>>() {
#Override
protected void onSuccessfulResult(List<Object> results) {
// whatever should happen on success
}
#Override
protected void onNonCancellationFailure(Throwable throwable) {
// whatever should happen on failure
}
});
Guava also has a bunch methods such as #successfulAsList which only contains successful results or #inCompletionOrder which orders them based on when they completed and a bunch of others.
I generally tend to use Guava as it provides a fairly clean solutions to problems like these.
An example of how to creates a ListenableFuture is as follows:
ListeningExecutorService service = MoreExecutors.listeningDecorator(Executors.newFixedThreadPool(10));
ListenableFuture<Object> explosion =
service.submit(
new Callable<Object>() {
public Object call() {
// get network data
return null; // return the data
}
});

How to call method in thread time after time?

I have a method that loads data from Firebase into ArrayList. After this,I use that ArrayList to construct RecyclerView. I've decided to load data on another thread. Below is my code:
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_just);
citiesRecyclerView =
(RecyclerView)findViewById(R.id.recyclerView);
handler = new Handler()
{
#Override
public void handleMessage(Message msg) {
super.handleMessage(msg);
if(msg.what==1)
{
cityAdapter = new
CityAdapter(MainActivity.this,cities) ;
citiesRecyclerView.setAdapter(cityAdapter);
}
}
};
t = new Thread(new Runnable() {
#Override
public void run() {
//method that loads data into List.If this method was
//successfully done,then I send message 1 to Handler
loadDataFromFirebase();
}
});
t.start();
//other operations below
}
Hope,that everything understandable. Code works fine. And my problem is that I need to use loadDataFromFirebase method in thread again. I wanted to call t.start() again in order to call loadDataFromFirebase method,but there was error that thread already started. I checked that by writing this code:
if(t.getState()== Thread.State.NEW)
t.start();
else
someMethod();
else statement worked above.
And my questions are:
1) Does loadDataFromFirebase method work really on another thread by this way?
2) How to call loadDataFromFirebase method again in another thread, if something happened? Do I need to create another variable for Thread again?
It's not a good idea to handle all low-level thread work by your own.
Accroding to Android you could:
Use AsyncTask (but notice that they have many drawbacks such as context leak in some cases etc),
I could suggest you to get into RxJava - it's a painless way to use async work in your app.
To 'download' data from Firebase you could probably use FCM (push notifications) to load data on demand.
And what about your question:
"It is never legal to start a thread more than once. In particular, a thread may not be restarted once it has completed execution."(c) http://docs.oracle.com/javase/6/docs/api/java/lang/Thread.html#start()
If you are using firebase SDK you can use realtime database feature, so do not need to query it each time.
You should just subscribe one time and get updates. For example:
firebaseReference.addValueEventListener(new ValueEventListener() {
#Override
public void onDataChange(DataSnapshot dataSnapshot) {
// This method is called once with the initial value and again
// whenever data at this location is updated.
YourDataObject value = dataSnapshot.getValue(YourDataObject.class);
Log.d(TAG, "Value is: " + value);
}
#Override
public void onCancelled(DatabaseError error) {
// Failed to read value
Log.w(TAG, "Failed to read value.", error.toException());
}
});
You can read docs here.

How to wait for webview.post to complete?

In the below code, outside is printed before inside. I want the order to be inside first and then outside. So how do I ensure that the Runnable is finished before the second Log is reached?
webView.post(new Runnable() {
#Override
public void run() {
Log.d("check", "inside");
}
});
// some code needed here
Log.d("check", "outside");
Some code must be inserted where to comment is to achieve this.
EDIT: I am doing all the work in a background service.
[P.S.: Those who are curious as to why I am doing this, it is so because unless I add the webview.post, I keep getting the following error: "All WebView methods must be called on the same thread.". Anyway, this shouldn't affect you from answering the question.]
You might try using a CountDownLatch:
final CountDownLatch latch = new CountDownLatch(1);
webView.post(new Runnable() {
#Override
public void run() {
Log.d("check", "inside");
latch.countDown();
}
});
// some code needed here
latch.await();
Log.d("check", "outside");
However, you wouldn't want to use latch.await() on the UI thread, as that's a blocking method. If you wanted to run this on the UI thread it would be best to replace latch.countDown() with a call to a callback method, which would in turn run Log.d("check", "outside").

Android: Send request to server every x minutes, update UI accordingly

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

Categories

Resources