Consider the following example Activity:
public class ExampleActivity extends Activity {
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_info);
new ExampleTask().execute("");
// code line 1
// code line 2
// code line 3
// code line 4
}
public class ExampleTask extends AsyncTask<String, Void, String> {
#Override
protected String doInBackground(String... address) {
// some long-running stuff
return "";
}
protected void onPostExecute(String text) {
}
}
}
With
new ExampleTask().execute("");
we start an AsyncTask which runs off the UI thread. We can not predict when it will be finished. The AsyncTask's onPostExecute method runs on the UI thread again.
Let's say the AsyncTask is done while code line 2 of the onCreate method is being executed.
When will the onPostExecute method be executed? Does it wait until onCreate is done or will it be executed immediately?
I think this question could be generalized to how Java (or at least Android) handles Threads that run off the main thread but return to the main thread and how Java/Android schedules two sequences of code that are 'competing' for immediate excution.
Thus it would be nice if an answer would provide a little general insight.
you can see it all for your self here:
https://android.googlesource.com/platform/frameworks/base/+/refs/heads/master/core/java/android/os/AsyncTask.java
// that's on the background thread
line #288: return postResult(doInBackground(mParams));
private Result postResult(Result result) {
#SuppressWarnings("unchecked")
Message message = sHandler.obtainMessage(MESSAGE_POST_RESULT,
new AsyncTaskResult<Result>(this, result));
// here it sends the message to the intenral UI handler
message.sendToTarget();
return result;
}
that means:
the AsyncTask post a message to its own internal UI handler, that means that onPostExecute will only be executed after everything else that is queued on the UI Looper gets executed
It will be called after onCreate() finishes because any callbacks on the UI thread are processed sequentially. So, first goes onCreate() then onPostExecute()
However, it seems, this is an implementation detail and you should not rely on that.
onPostExecute will be called, immediately after the task completion in the doInBackground method. see details about AsyncTask
Let's say the AsyncTask is done while code line 2 of the onCreate method is being executed. When will the onPostExecute method be executed? Does it wait until onCreate is done or will it be executed immediately?
Yes it does wait for onCreate completion, onPostExecute will be called after the onCreate method.
Related
I am tried to search about AsyncTack. How to Update UI after asyntack execute.
Example : I have 2 java file.
file 1 : Myfragment.java, file 2 : MyAsyntack.java
in this case, i'm execute MyAsyntack on MyFragment. after Execute, I want to update UI.
On MyAsyntack, I'am updating database (doing in background). Any body can help?
You can set an interface in AsyncTask and call it in onPostExecute of it to update UI.
public inteface UpdateUI()
{
public void update();
}
then in your AsyncTask declare an updateUI like this:
UpdateUI updater;
public MyAsyntack (UpdateUI updater)
{
this.updater = updater;
}
#Override
protected void onPostExecute(String result)
{
super.onPostExecute(result);
updater.update();
}
and finally in your activity:
MyAsyntack myAsyncTask = new MyAsyntack(new UpdateUI(){
//how you want to update UI
}
);
myAsyncTask.execute();
doInBackground() is on worker thread and can be used to do heavy tasks like network calls to server.
When data is fetched, you can update the UI from onPostExecute(..) which is on the UI thread.
p.s. return of doInBackground will be argument to onPostExecute(..)
I am using AsyncTask to run a background operation. Of course switching to another thread while already working in a background thread does not make a lot of sense in general, except the other thread is the UI thread. This what I would like to to: While the task is running I need to "access" the UI, e.g. to show a dialog to ask the user how to proceed.
run the background task
stop the task at some point to get user feedback
switch to the UI thread to show dialog and ask for input
switch back to background task and continue work
How can this be done? I thought I could use Runnable with myActivity.runOnUiThread(runnable) but this does not work:
private void copyFiles() {
CopyTask copyTask = new CopyTask(this);
copyTask.execute();
}
// CustomAsyncTask is a AsyncTask subclass that takes a reference to the current
// activity as parameter
private class CopyTask extends CustomAsyncTask<Void, Void, Void> {
private doCopy;
#Override
protected Boolean doInBackground(Void... params) {
// Custom code, e.g. copy files from A to B and check for conflict
for (File file : allFiles) {
doCopy = true;
if (isConflict(file)) {
// Stop current thread and ask for user feedback on UI Thread
Runnable uiRunnable = new Runnable() {
public void run() {
// Pos 1. --> Execute custom code, e.g. use AlertDialog to ask user if file should be replaced...
doCopy = false;
synchronized (this) {
this.notify();
}
}
});
synchronized(uiRunnable) {
// Execute code on UI thread
activity.runOnUiThread(uiRunnable);
// Wait until runnable finished
try {
uiRunnable.wait();
}
catch (InterruptedException e ) {
e.printStackTrace();
}
}
}
// Pos 2. --> Continue work
if (doCopy)
copyFromAToB(File);
}
return null;
}
}
Within doInBackground() (--> in a background thread) the AsyncTask calls activity.runOnUiThread(uiRunnable). Next uiRunnable.wait() is called. Regarding to the docu wait() should do the following:
Causes the calling thread to wait until another thread calls the
notify() or notifyAll() method of this object.
Thus the background thread should wait to continue its work until this.notify() (== uiRunnable.notifiy()) is called on another thread (= the UI thread), shouldn't it?
Well, id does not wait! After calling uiRunnable.wait() the background thread immediately continues by jumping to if (doCopy).... It seems that the background thread and the main thread are executed in parallel (not surprising since this is what thread do...) and thus its a race condition whether doCopy = false on the UI thread or if (doCopy) on the background thread is reached first.
How is this possible? Why doesn't wait() works as described? Or am I getting something wrong?
Thank you very much!
EDIT:
To avoid missunderstandings: Of course I know the lifecycle methodes of AsyncTask but as far as I understand them, they are not what I am looking for (see my reply to the comment blow).
Interrupting the AsyncTask as soon as a UI interaction is necessary, query the UI and start a new AsyncTask would be possible of course. However this would result in code which is very hard to read/understand/maintain.
As I understand the docu of wait() everything should work fine here. Primary question is not how to do UI interaction during the lifecycle of an AsyncTask but why wait()does not work as expected.
The Basics
When you start an AsyncTask first the onPreExecute() method runs on the UI thread. You can override this method to make changes to the UI prior to the doInBackground() method running.
After the doInBackground() method finishes, the onPostExecute() method runs on the UI thread, so you can use this to make changes to the UI from here. If you need to make regular changes to the UI Thread during the doInBackground() method you override the onProgressUpdate() method which runs on the UI Thread, and then call it from within doInBackground(), which will allow you to periodically update the UI.
You could use something like the following;
private class DoStuffTask extends AsyncTask {
#Override
protected void doInBackground(Object... args) {
// Do stuff
onProgressUpdate(x);
// Do more stuff
}
#Override
protected void onProgressUpdate(Object... args) {
// Update your UI here
}
}
Now if this doesn't quite do it and you want the AsyncTask to wait for input during the doInBackground() method it is probably worth considering using multiple AsyncTasks instead. You can then finish each AsyncTask, ask for input, and then start a new AsyncTask to continue working.
Given that AlertDialog instances are asynchronous, this is probably the preferred solution because you can start the next AsyncTask from the AlertDialog itself.
Using wait() in an AsyncTask
If you would prefer to use a single AsyncTask you can use wait from within your AsyncTask to prevent execution continuing until some condition is met. Instead of using a new Runnable we are just using two threads in this instance, the thread running doInBackground() and the main thread, and we are synchronizing on the AsycTask itself.
Example below;
public class TestTask extends AsyncTask{
private boolean notified;
private Promptable p;
public interface Promptable { public abstract void prompt(); }
public TestTask(Promptable p){
this.p = p;
}
#Override
protected Object doInBackground(Object... arg0) {
Log.d("First", "First");
onProgressUpdate(null);
synchronized(this){
while(!notified){
try{
this.wait();
}
catch(InterruptedException e){ }
}
}
Log.d("Second", "Second");
return null;
}
#Override
protected void onProgressUpdate(Object... args){
synchronized(this){
notified = true;
p.prompt();
this.notify();
}
}
}
In the example above, assume that your Activity is parsed into the AsyncTask's constructor, and that it implements an interface we create called Promptable. You'll notice that even though we're calling wait() we are putting it in a while loop. If we didn't do this, and somehow notify() got called before wait() then your thread would lock up indefinitely. Also, you can't depend on the fact that your thread will wait forever, so the while loop ensures that it doesn't continue until notify is called.
I hope this helps.
I have been searching for the answer but no one really answers because there is no point using async task for that. In Android API 11 or above it will force to code it you do network requests on the main thread so I have to do async task. So, here is the question: Is it possible to wait untill the async task is finished then continue? Because I need the data to be there for the calling method etc.
Here is my code:
public JSONObject getJSONFromUrl(String url) {
this.url = url;
new loadURL().execute();
// Do this when ASYNC HAS FINISHED
return jObj;
}
class loadURL extends AsyncTask <Void, Void, Void> {
protected void onPreExecute() {
}
protected Void doInBackground(Void... unused) {
//do stuff in background
return (null);
}
}
}
Any questions to answer just leave a comment. Thanks for helping.
yes you use the onPostExecute method of the AsyncTask to do whatever you want to do after. That method gets called after the doInBackground is finished
If the operation won't take long (less than a few seconds) you can use the progress bar to keep from allowing the user to do anything. Set something like this in your AsyncTask
ProgressDialog progress = ProgressDialog.show(LoginScreen.this, "Downloading Users", "Please wait while users are downloaded");
#Override
protected void onPreExecute()
{
progress.setCancelable(false);
progress.isIndeterminate();
progress.show();
}
You will still want to call your method from onPostExecute() as this will just keep the user from being able to do anything but it won't keep any code from running that is in the method you calling the AsyncTask from
This can be done with wait(), notify() and notifyAll() methods of objects. Or You can use custom callbacks via interfaces. Just call proper method via callback when you complete getting required data.
You can perform Network related operation inside doInBackground() method because onPostExecute() method is used only for UI updation only in android
I have an AsyncTask that downloads files in doInBackground() method. I am testing my app before releasing it. When I manually force quit the app and relaunch it, the doInBackground() seems to be invoked, but not onProgressUpdate() and onPostExecute(). My onPostExecute() call methods that cause UI changes.
How can I make sure the onPostExecute and onProgressUpdate() get called? I also see the following warning:
Activity stop timeout for ActivityRecord or Activity destroy timeout for ActivityRecord or Activity idle timeout for ActivityRecord
Code:
public void OnCreate(){
new RefreshMyDashboardTask().execute();
}
private class RefreshMyDashboardTask extends AsyncTask<Void, Void, Long> {
#Override
protected void onPreExecute() {
}
#Override
protected void onProgressUpdate(Void... params) {
super.onProgressUpdate(params);
}
#Override
protected Long doInBackground(Void... params) {
// my server calls are called here.
}
#Override
protected void onPostExecute(Long result) {
}
}
If you kill your app, or if the system kills it, then AsyncTask threads for your app get killed. They're all part of your app's process; threads can't survive outside the process that started them.
Even an IntentService might not survive a force quit. That's why task killers are such a bad idea.
In short, what you're seeing is expected behavior.
i bascially have an activity
that calls an async task to set up the twitter classes, provided via twitter4j.
But i recieve an error regarding "cant create handler inside thread that has not called looper.prepare "
which is orginating from the TwitterApp class where there is a handler...
how can i get around this? successfully setting up the class no on the main UI thread as i used to have before (which worked perfectly but slowed down the app);
im basically doing:
new SetUpAsyncTaskt().execute();
within the asynctask all im doing is:
TwitterApp mTwitter;
postToTwitter = true;
String twitter_consumer_key="bllaalaa";
String twitter_secret_key="blaa"
private class SetUpAsyncTask extends AsyncTask<Void, Void, Void> {
#Override
protected Void doInBackground(Void... params) {
mTwitter = new TwitterApp(context, twitter_consumer_key,twitter_secret_key);
mTwitter.setListener(mTwLoginDialogListener);
return null;
}
#Override
protected void onPostExecute(Void result) {
if(!mTwitter.hasAccessToken()){
postToTwitter=false;
}
}
}
Thanks for any help!
UPDATE: After doing more testing, it seems the problem is due to the context, as if i remove all context based data within the class it works, but what i dont get is if i pass in the context from the UI thread, it still occurs ?? :S
UPDATE2: Found another way around it, thanks to all who replied.
Look here for the documentation: http://developer.android.com/reference/android/os/AsyncTask.html
some rules:
The task instance must be created on the UI thread.
execute(Params...) must be invoked on the UI thread.
My guess is you are executing the task on some different thread. To Execute it on UI thread create a Handler in onCreate and:
mHandler.post(new Runnable(){
//insert task creation & execution here
});
In this way the result that are in onPostExecute will be returned on the UI Thread too.
You can use runOnUiThread() to make the non-UI task run on the UI,
Try this,
#Override
protected Void doInBackground(Void... params) {
mTwitter = new TwitterApp(context, twitter_consumer_key,twitter_secret_key);
Activity_name.this.runOnUiThread(new Runnable() {
#Override
public void run() {
mTwitter.setListener(mTwLoginDialogListener);
}
});
return null;
}