I want to make downloader, which download data and then call function in UI thread. I have this in main activity
onCreate(){
...
dataRepository.downloadIfNewOrEmpty(new DownloadResponse() {
#Override
public void SuccessResponse(Response response) {
// do something in UI
}
});
}
My function downloadIfNewOrEmpty looks for now only simple with sleep()
public void downloadIfNewOrEmpty(final DownloadResponse response){
//final Handler handler = new Handler();
new Thread(new Runnable() {
#Override
public void run() {
try {
Thread.sleep(5000);
response.SuccessResponse(ResponseCode.SUCCESS);
/*handler.post(new Runnable() {
#Override
public void run() {
response.SuccessResponse(ResponseCode.SUCCESS);
}
});*/
}catch (Exception e){
// Log...
}
}
}).start();
}
If I run this code, it normally does the job and update my UI. I found this solution with Handler (android.os.Handler) but if I run it without or with Handler (commented version) it works same.
Although without handler function SuccessResponse is run in UI thread?
Thank you
Although without handler function SuccessResponse is run in UI thread?
Yes, because response is instance of DownloadResponse which is passed from UI Thread as parameter to downloadIfNewOrEmpty.
Related
here is my piece of code:
Thread one = new Thread() {
public void run() {
try {
new LongOperation(finalJson)
.executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR)
.get(30000, TimeUnit.MILLISECONDS);
} catch (InterruptedException e) {
e.printStackTrace();
} catch (ExecutionException e) {
e.printStackTrace();
} catch (TimeoutException e) {
e.printStackTrace();
}
}
};
one.start();
i want to say if AsyncTask past 30000 MILLISECONDS and didn't finish the job return a message, how i can code this? thanks
I would prefer doing it using an AsyncTask.
Copy-pasting from the link:
AsyncTask enables proper and easy use of the UI thread. This class
allows you to perform background operations and publish results on the
UI thread without having to manipulate threads and/or handlers.
AsyncTask is designed to be a helper class around Thread and Handler
and does not constitute a generic threading framework. AsyncTasks
should ideally be used for short operations (a few seconds at the
most.) If you need to keep threads running for long periods of time,
it is highly recommended you use the various APIs provided by the
java.util.concurrent package such as Executor, ThreadPoolExecutor and
FutureTask.
Said this, configuring an AsyncTask is pretty simple, just create a class like the following:
private class LongOperation extends AsyncTask<String, Void, String> {
#Override
protected void onPreExecute() {
super.onPreExecute();
//this method works on the UI thread.
//this is the first to run before "doInBackground"
mTextView.setText("we start!");
}
#Override
protected String doInBackground(String... params) {
try {
//do whatever your async task needs to do. This method works async
//you can also call an UI callback from here with the publishProgress method. This will call the "onProgressUpdate" method, and it has to respect his type.
publishProgress("we go on!");
} catch (InterruptedException e) {
Thread.interrupted();
}
return "Executed";
}
#Override
protected void onPostExecute(String result) {
//this method works on the UI thread
//it get the "doInBackground" return value.
mTextView.setText(result);
}
#Override
protected void onPreExecute() {}
#Override
protected void onProgressUpdate(String... values) {
//this method works on UI thread, so it can access UI components and ctx
mTextView.setText(values[0]);
}
}
This is a basic example on how to create an AsyncTask, you can use it like this (form activity/fragment):
AsyncTaskExample asyncTask = new AsyncTaskExample();
asyncTask.get(30000, TimeUnit.MILLISECONDS);
This will set a timeout on your async operation. Look here for the exact Exception/return
For any further question, ask freely. Hope this helps
Edit:
I just noticed you have an AsyncTask inside your thread. Since AsyncTask is already async, I would avoid doing this and simply call the AsyncTask with the method I gave you before. In that way the AsyncTask will run up to the given TimeSpan :)
See the code below: It may help you.
CountDownTimer timer = new CountDownTimer(3000,1000) {
#Override
public void onTick(long l) {
}
#Override
public void onFinish() {
//return a message here;
}
};
timer.start();
And if you have an async task. Then do like below in doInBackground method:
#Override
protected Void doInBackground(Void... voids) {
//simply do your job
CountDownTimer timer = new CountDownTimer(3000,1000) {
#Override
public void onTick(long l) {
}
#Override
public void onFinish() {
//return a message here;
return message;
}
};
timer.start();
return your_reult;
}
I have a handler for a thread in my MainActivity that calls a method named UpdateGUI.
Both the handler/thread declaration and the method are within the MainActivity.
This is the handler Declaration:
Handler handlerData = new Handler();
private Runnable runnableCode2 = new Runnable() {
#Override
public void run() {
Log.d("Handlers","GET TOTAL RX BYTES: "+Long.toString(res) );
//Some code here that doesn't matter/
UpdateGUI();
}
handlerData.postDelayed(runnableCode2, 1*6000);
}
};
And UpdateGUI is as follows:
public void UpdateGUI(){
Log.d("Updater", "STARTING UPDATE");
//Code that doesn't matter here}
}
From the logger I can see that UpdateGUI() is not being called from the thread. Can you explain why this is happening and how it can be fixed?
Just to clarify. The thread is running,but for some reason it doesn't make the call to UpdateGUI().
You need to atleast run handler once then only it will continuously called from the handler runnable method.
so call handler.post(runnableCode2); once in your code and that will be repeated
handlerData.postDelayed(runnableCode2, 1*6000);
hope this will resolved your issue.
I cant see you starting the Runnable.
Handler handlerData = new Handler();
private Runnable runnableCode2 = new Runnable() {
#Override
public void run() {
Log.d("Handlers","GET TOTAL RX BYTES: "+Long.toString(res) );
//Some code here that doesn't matter/
UpdateGUI();
}
handlerData.postDelayed(runnableCode2, 1*6000);
}
};
// This part is missing
handlerData.postDelayed(runnableCode2, 1000);
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,
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
}
}
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.
In the last days I have found myself using this approach for asynchronously performing some long operation (several seconds), and then return some value via a callback that must execute on the caller thread, which is typically but not necessarily the UI thread.
public abstract class DoSomethingCallback
{
public abstract void done(Object result);
}
public void doSomething(final Object param, final DoSomethingCallback doSomethingCallback)
{
// Instantiate a handler for the calling thread
final Handler handler = new Handler();
// Start running the long operation in another thread
new Thread(new Runnable() {
#Override
public void run() {
// Do a long operation using "param" as input...
Object result = longOperation(param);
// Return result via a callback, which will run in the caller thread
handler.post(new Runnable() {
#Override
public void run() {
doSomethingCallback.done(clearBytes);
}
});
}
}).start();
}
This seems to work pretty well and is very simple to use. However, I somehow suspect it might have some problems I'm not aware of. So the question is, what are the potential issues of this approach? What are better alternatives than manually creating and running a thread? I'm seeking for simplicity and robustness.
The only problem is that such approach breaks encapsulation: the second thread not only computes the result, but also dictates what the caller thread should do with it. So I'd better refactor your code as follows:
public abstract class DoSomethingCallback {
final Handler handler = new Handler();
public void post(final Object result) {
handler.post(new Runnable() {
#Override
public void run() {
doSomethingCallback.done(result);
}
});
}
public abstract void done(Object result);
}
public void doSomething(final Object param, final DoSomethingCallback doSomethingCallback) {
// Instantiate a handler for the calling thread
final DoSomethingCallback handler = new DoSomethingCallback () {
void done(Object result) {
...
}
};
// Start running the long operation in another thread
new Thread(new Runnable() {
#Override
public void run() {
// Do a long operation using "param" as input...
Object result = longOperation(param);
// Return result via a callback, which will run in the caller thread
handler.post(result);
});
}
}).start();
}
When I run the application with eclipse it shows me an error: "can't create handler inside thread that hos not called looper.prepare()" and I do not understanding why.
This is a part of my code
public void execute_web_service() {
progressd = ProgressDialog.show(liste_voyage.this, "", "Chargement...", true,
false);
Thread thread = new Thread(liste_voyage.this);
thread.start();
}
public void run() {
get_liste_arrives();
handler.sendEmptyMessage(0);
}
private Handler handler = new Handler() {
#Override
public void handleMessage(Message msg) {
progressd.dismiss();
afficher_liste_arrives();
}
};
You will get this error, with the above code, if the code that is creating an instance of this class is running on a thread other than the main application thread.