Reputation: 706
I am currently creating an Android app and encounter an issue and I haven't solved yet.
I use the Retrofit library to send requests to a server, according to the Retrofit library it is done in a background thread.
I call this Retrofit request in the main thread and I want to wait for this background thread to finish in order to work on its output.
I found a similar question on the forum but I don't know how to implement : Android: how to wait AsyncTask to finish in MainThread?
I call the request with Retrofit, when the request is finished, the success method of the Callback object starts, but main thread is still running and it reaches the last line before the background task has finished.
How can I force my main thread to wait for the background task to finish ?
My code :
// ... (main thread)
// CALL TO THE SERVER
RestAdapter restAdapter = new RestAdapter.Builder()
.setEndpoint(LoginScreen.ENDPOINT).build();
WebServices getFiles = restAdapter.create(WebServices.class);
Callback<Response> callback = new Callback<Response>()
{
@Override
public void success(Response s, Response response)
{
fileAvailable = new String(((TypedByteArray) s.getBody()).getBytes());
//THIS IS EXECUTED WHEN THE BACKGROUND TASK IS FINISHED
}
@Override
public void failure(RetrofitError retrofitError)
{
Log.e(TAG, retrofitError.toString());
}
};
getFiles.getFiles(id, callback);
// I want here to work with fileAvailable, but the code
// reaches this line before the background task is over.
I tried to create a Handler object as in the previous link and call sendEmptyMessage in the success method but it didn't work.
I would be really grateful if somebody could help me.
Thank you in advance,
Upvotes: 3
Views: 7952
Reputation: 9284
You don't want to block your main thread, that's the whole point of this library. You need to reconsider how you do this because if you block the main thread the UI will hang (be unresponsive) and the user will be upset. Think about the last time you used an app and everything locked up for several seconds. That is what happens if you block the main thread.
Instead, you should continue your logic in the response handler, or you can call into a function of the outer class from the inner class (callback is the inner class).
RestAdapter restAdapter = new RestAdapter.Builder()
.setEndpoint(LoginScreen.ENDPOINT).build();
WebServices getFiles = restAdapter.create(WebServices.class);
Callback<Response> callback = new Callback<Response>()
{
@Override
public void success(Response s, Response response)
{
fileAvailable = new String(((TypedByteArray) s.getBody()).getBytes());
doSomethingOnSuccess();
}
@Override
public void failure(RetrofitError retrofitError)
{
Log.e(TAG, retrofitError.toString());
}
};
//this runs before success(), so show a spinner or something,
//eg:http://stackoverflow.com/questions/9157504/put-a-progressbar-on-actionbar
}
-- Update (per your comment about having multiple background tasks -- If you've got 2 or more background tasks running in parallel (meaning they don't depend on each others output) but you need all of them to complete before you can do anything with them, it would probably look like this:
public class MyActivity extends Activity {
private Result result1 = null;
private Result result2 = null;
public void onCreate(Bundle savedState) {
super.onCreate(savedState);
Callback<Response> callback1 = new Callback<Response>() {
@Override
public void success(Response s, Response response)
{
result1 = new String(((TypedByteArray) s.getBody()).getBytes());
checkComplete();
}
@Override
public void failure(RetrofitError retrofitError)
{
Log.e(TAG, retrofitError.toString());
}
};
Callback<Response> callback2 = new Callback<Response>() {
@Override
public void success(Response s, Response response)
{
result2 = new String(((TypedByteArray) s.getBody()).getBytes());
checkComplete();
}
@Override
public void failure(RetrofitError retrofitError)
{
Log.e(TAG, retrofitError.toString());
}
};
getFiles.getFiles(id, callback1);
otherthing.doSomething(id, callback2);
}
private void checkComplete() {
if (result1 != null && result2 != null) {
doSomethingWithResults();
}
}
private void doSomethingWithResults() {
//update UI
}
}
Upvotes: 3
Reputation: 21036
There's no "last line" for the main thread, it's ongoing. Main thread is not finished after onCreate()
is done executing. Just put the code you want to execute on the data into the success handler right where
//THIS IS EXECUTED WHEN THE BACKGROUND TASK IS FINISHED
is.
Upvotes: 0