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
Related
Can't find much about this concept. Have already referred to
https://android.googlesource.com/platform/frameworks/base/+/master/core/java/android/os/AsyncResult.java
https://docs.oracle.com/javaee/6/api/javax/ejb/AsyncResult.html
Edit: I believe the AsyncResult I was referring to was the particular name chosen to hold the result from a generic asynchronous operation. (Background operation that will asynchronously notify the user when it is done.)
It seems the links above are just particular implementations of this concept.
For reference, see these instead:
Developer.android.com - AsyncTask
Developer.android.com - Processes and Threads
Background / Theory
AsyncTask allows you to run a task on a background thread, while publishing results to the UI thread.
The user should always able to interact with the app so it is important
to avoid blocking the main (UI) thread with tasks such as
downloading content from the web.
This is why we use an AsyncTask.
It offers a straightforward interface by wrapping the UI thread message queue and handler that allow you to send and process runnable objects and messages from other threads.
Implementation
AsyncTask is a generic class. (It takes parameterized types in its constructor.)
It uses these three generic types:
Params - the type of the parameters sent to the task upon execution.
Progress - the type of the progress units published during the background computation.
Result - the type of the result of the background computation.
Not all types are always used by an asynchronous task. To mark a type as unused, simply use the type Void:
private class MyTask extends AsyncTask<Void, Void, Void> { ... }
These three parameters correspond to three primary functions you can override in AsyncTask:
doInBackground(Params...)
onProgressUpdate(Progress...)
onPostExecute(Result)
To execute AsyncTask
call execute() with parameters to be sent to the background task.
What Happens
On main/UI thread, onPreExecute() is called. (To initialize something in this thread such as show a progress bar on the user interface.)
On a background thread, doInBackground(Params...) is called. (The parameters are those passed to the Execute function.)
Where the long-running task should happen
Must override at least doInBackground() to use AsyncTask.
Call publishProgress(Progress...) to update a display of progress in the user interface while the background computation is still executing. (e.g. animate a progress bar or show logs in a text field.)
This causes onProgressUpdate() to be called.
On the background thread, a result is returned from doInBackground(). This triggers the next step.
On main/UI thread, onPostExecute() called with the returned result.
Examples
Using again the example of the blocking task being to download something from the web,
Example A downloads an image and displays it in an ImageView,
while Example B downloads some files.
Example A
The doInBackground() method downloads the image and stores it in an object of type BitMap. The onPostExecute() method takes the bitmap and places it in the ImageView.
class DownloadImageTask extends AsyncTask<String, Void, Bitmap> {
ImageView bitImage;
public DownloadImageTask(ImageView bitImage) {
this.bitImage = bitImage;
}
protected Bitmap doInBackground(String... urls) {
String urldisplay = urls[0];
Bitmap mBmp = null;
try {
InputStream in = new java.net.URL(urldisplay).openStream();
mBmp = BitmapFactory.decodeStream(in);
} catch (Exception e) {
Log.e("Error", e.getMessage());
e.printStackTrace();
}
return mBmp;
}
protected void onPostExecute(Bitmap result) {
bitImage.setImageBitmap(result);
}
}
Example B
private class DownloadFilesTask extends AsyncTask<URL, Integer, Long> {
protected Long doInBackground(URL... urls) {
int count = urls.length;
long totalSize = 0;
for (int i = 0; i < count; i++) {
totalSize += Downloader.downloadFile(urls[i]);
publishProgress((int) ((i / (float) count) * 100));
// Escape early if cancel() is called
if (isCancelled()) break;
}
return totalSize;
}
protected void onProgressUpdate(Integer... progress) {
setProgressPercent(progress[0]);
}
protected void onPostExecute(Long result) {
showDialog("Downloaded " + result + " bytes");
}
}
Example B execution
new DownloadFilesTask().execute(url1, url2, url3);
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.
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 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;
}