Getting results from an AsyncTask - android

I'm trying to use AsyncTask to download a string and return the string. I want to use AsyncTask because it might take a while.
One problem is that nowhere on the internet can I find an example of an AsyncTask returning any kind of value. So I took the example in the Commonsware book and modified it to return a value and I get the value as follows:
String mystr = new AddStringTask().execute().get();
While this works, it seem that this line of code is waiting for the return value and therefore synchronous. There must be some way to have an event trigger with the results of the AddStringTask.
How is that done?
Thanks, Gary

An AsyncTask cannot return a value, because to get the returned value you would have to wait before the task is finished. That would make the AsyncTask meaningless.
Instead, you should move your code in onPostExecute() (which runs on the UI thread, if this is what you worry about). This is where you handle the value returned by doInBackground() and typically update the UI or show an error message.

Also if you wanted to implement a more general AsyncTask you could implement something like the following to compartmentalize your code inside the activity.
#Override
protected void onPostExecute(Bitmap r){
if (r != null) {
processListeners(r);
}
}
protected void processListeners(Object data) {
for (final AsyncTaskDone l : listeners) l.finished(data);
}
public void addAsyncTaskListener (final AsyncTaskDone l){
listeners.add(l);
}
Where AsyncTaskListener is an interface with one function called finished implemented in the Activity the same way an onClickListener would be.

Related

How to do or do nothing base on AsyncTask result?

Experts,
My goal is simple, input an address, click a button to test a URL, if not get the expected result, a toast info and then do nothing. If get expect result, continue the program.
Since I can not use URL in UI thread, I used AsyncTask, the problem is: though I know the result from AsyncTak, how to inform activity to do or do nothing?
What I want is a statement inside the OnClickListener like this:
if (result is not expected) return; else continue do things.
I cannot write above statement in onPostExecute, it will return onPostExecute(), not onClickLIstener().
Another is: even if I can pass the result to activity(namely to onClickLIstener()), when the result arrives, probably UI thread already run some other codes, but they shouldn't before knowing the result.
In short, I need the URL result to decide how to run remaining codes, therefore cannot use async task, what should I do?
Thanks.
Below is the example code:
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
btnConfirm.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
new XXX().execute(code);
});
}
class XXX extends AsyncTask<String, Void, String> {
protected String doInBackground(String... strArr) {
XXXXX;
}
protected void onPostExecute(String result) {
XXXXX;
}
}
This should be easy. Try this approach:
Since you already have your AsyncTask as an inner class in your activity, you can easily return a result in onPostExecute() then check if request was successful or not.
Now, here is the final part: create a method in your activity like this:
private void executeOnAsyncSuccess(){
//place the code here you want to run
}
Now you can call it inside onPostExecute() easily!
You can also do this using Events but this approach should just work!
I hope this helps!
I just learned that maybe Callable is a good way, use its V get().

android autocomplete AsyncTask delay

I'm implementing a location suggestion activity which populates suggestions from an external server as the user types in a text view. I'm using an AsyncTask to fetch suggestions each time the text in the text view changes. When a new letter is typed, we cancel the task that already exists and execute a new one. Most of the time doInBackground starts immediately after execute is called, but other times it can take a few seconds. (Once doInBackground starts, performance is fine.)
Set listener:
private void init() {
// respond to any text change
textView.addTextChangedListener(new TextWatcher() {
#Override
public void onTextChanged(final CharSequence s, int start, int b, int c) {
showSuggestions(s.toString());
}
});
}
Here we start a new task and cancel the previous one:
private void showSuggestions(String query) {
// suggestionsTask is an instance variable of the activity
if (suggestionsTask != null) {
suggestionsTask.cancel(true);
}
suggestionsTask = new AsyncTask<String, Void, List<Suggestion>>() {
#Override
protected void onPostExecute(List<Suggestion> resultList) {
// set suggestions with adapter - CHANGES STATE
}
#Override
protected List<Suggestion> doInBackground(String... query) {
// one local db call for recent searches - DOES NOT CHANGE STATE
// one network call to external server - DOES NOT CHANGE STATE
// return results
}
};
suggestionsTask.execute(query);
}
Is there a better threading mechanism to use for this? Do you know why there is a delay between execute and doInBackground?
From the AsyncTask reference:
A task can be cancelled at any time by invoking cancel(boolean). Invoking this method will cause subsequent calls to isCancelled() to return true. After invoking this method, onCancelled(Object), instead of onPostExecute(Object) will be invoked after doInBackground(Object[]) returns. To ensure that a task is cancelled as quickly as possible, you should always check the return value of isCancelled() periodically from doInBackground(Object[]), if possible (inside a loop for instance.)
So you're actually not canceling the doInBackground() step unless you're manually checking whether isCancelled() is set periodically in doInBackground. In most versions of Android, all AsyncTasks share a single thread, so one has to finish before the next can start. So that's the reason for your delay, but I don't have enough information (i.e., you didn't post the code) from your doInBackground() code to come up with a suggestion on where to check for isCancelled().
If being able to cancel the previous task not possible for some reason, you can also try making your AsyncTasks execute in parallel, using executeOnExecutor(java.util.concurrent.Executor, Object[]) with THREAD_POOL_EXECUTOR as the same documentation suggests, but with what you're trying to do that seems like it could cause some frustrating threading issues which would probably be worse than the one you're having right now.

AsyncTask starts after function is finished

I just have a public function where I have some loops etc. and in the beginning of my function I start my AsyncTask which returns me a value which is needed in the near of the end of this function. But somehow the AsyncTask just starts after this function finished ? Is there a way to run the Asynctask before or parallel ? Until today I thought AsyncTask are normally running parallel. I found out the method
.get()
but this is freezing the thread ... I need an alternative or fix
public void my_function ()
{
new async_task().execute()
... //do something
if (returned_value_from_async_task == 10) //Here I need the variable which is returned in the async_task
{
... //do something
}
} //End of function
//When I go to debug mode the AsyncTask starts right here
Yes. Thats the "Async" part of AsyncTask. The code at the end of the function isn't going to wait for the task to finish. so you can't rely on that data to be there. The code you're running in your function probably takes less time than it takes the ThreadPoolExecutor to spool up your task.
Execute the code that depends on the data from the AsyncTask in onPostExecute
EDIT:
Without knowing what "more complex" means, it's hard to say what your best option is. But you could split the function, thusly
public void preExecutePrep() {
YourTask yourTask = new YourTask();
yourTask.execute();
//do what you can without the result
}
private void postExecuteCode(int result) {
if (result != 10) return;
//do the rest
}
then call postExecuteCode in onPostExecute. If this isn't going to cut it, I'll need more specific information to help

How to create a while(true) in a AsyncTask whithout blocking the Activity?

I have created an AsyncTask and I have to create an while(true) on my AsyncTask.
How can I execute such an unbounded loop upon handling a button click in my Activity class without blocking?
How others said a infinit loop without a break condition isn't a nice user experience.
First get a instance for your AsyncTask:
PostTask pt = new PostTask(this);
pt.execute();
Try this in your doInBackground():
while(!this.isCancelled()){
// doyourjobhere
}
If the app is getting closed by the user the AsyncTask have to be stopped in your onPause().
#Override
public void onPause(){
pt.cancel(false);
}
TheAsyncTask.cancel(boolean) sets isCancelled() to true, calls the AsyncTask.onCanceled() method instead of onPostExecute() and can be overwritten for your own purpose.
If you don't like this put your task in a Service.
As said by the others, you should put your 'infinite loop' inside the doInBackground() method of AsyncTask.
However, this loop is not so infinite, because it must end when you exist the activity, or the application.
I suggest changing your while (true) { } to while (! mustStop) { } and set the boolean mustStop as an instance variable of your activity. So you'll be able to cleanly stop the process by setting mustStop=true (it would be a good idea to set this in the onPause method).
So this will be :
public class AsyncBigCalculActivity extends Activity {
private boolean mustStop = false;
#Override
public void onPause() {
super.onPause();
mustStop=true; // Stop the infinite loop
}
....
#Override
protected String doInBackground(String... params) {
mustStop=false;
while (!mustStop) {
...
}
}
you can put the loop within the doInBackground() method of the AsyncTask. As a suggestion, you can add the AsyncTask as an inner class within your Activity.That way you can easily access the variables declared in your activity. Although the android documentation suggests to use AsyncTask only for short tasks. Its more advisable to create a runnable object and put your while loop within the run() method and execute it using ExecutorService, which allows you to run asynchronous code in android in a thread-safe manner.
http://docs.oracle.com/javase/6/docs/api/java/util/concurrent/ExecutorService.html
http://developer.android.com/reference/java/util/concurrent/ExecutorService.html

Check if all AsyncTasks have finished

I have 3 AsyncTasks and 1 ProgressBar. I want when any of task executes, the progress bar is visible and when all of them finish, the progress bar is invisible.
In Java, there is ExecutorService::isTerminated to check if all runnables finished but Android doesn't have it.
Update: 3 tasks execute at the same time.
Figure.
Nice graphic. But I am afraid there is no build in mechanism for this. You'll have to implement it by yourself. There are few solutions you could use -
Keep a reference to all 3 task. When task finishes check if the other two tasks are finished too, if yes than close the progress dialog if no wait for some other task to finish and check again. Make sure you free the references when you're done.
If you don't want to keep a reference store a counter. When the task finishes, increment the counter and check if it's equal to 3. If all tasks finished and you are done. If you implement this make sure to synchronized the access to the counter.
Try using AsyncTask.getStatus(). This works perfectly fine. Refer below sample code.
List<AsyncTask<String, String, String>> asyncTasks = new ArrayList<AsyncTask<String, String, String>>();
AsyncTask<String, String, String> asyncTask1 = new uploadTask().execute(string);
AsyncTask<String, String, String> asyncTask2 = new downloadTask().execute(string);
AsyncTask<String, String, String> asyncTask3 = new createTask().execute(string);
asyncTasks.add(asyncTask1);
asyncTasks.add(asyncTask2);
asyncTasks.add(asyncTask3);
You can later loop the AsyncTaskList and find each of the tasks' status as below.
for(int i=0;i<asyncTasks.size();i++){
AsyncTask<String, String, String> asyncTaskItem = (AsyncTask<String, String, String>)asyncTasks.get(i);
// getStatus() would return PENDING,RUNNING,FINISHED statuses
String status = asyncTaskItem.getStatus().toString();
//if status is FINISHED for all the 3 async tasks, hide the progressbar
}
A simple workaround would be to use three boolean variables one each for each AsyncTask and then check them accordingly.
A better approach would be to create a separate class that extends AsynTask and defines a callback interface which is fired in onPostExecute.
create a field to hold all tasks:
private ArrayList<HtmlDownloaderTask> mTasks;
Start your tasks this way:
HtmlDownloaderTask = new HtmlDownloaderTask(page.getHtml());
task.execute(page.getUrl());
//if you want parallel execution try this:
//task.executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR,page.getUrl());
mTasks.add(task);
on the onPostExecute of MyAsyncTask:
int unfinishedTasks = 0;
for (HtmlDownloaderTask myDT : mTasks){
if(!(myDT.getStatus() == AsyncTask.Status.FINISHED)){
unfinishedTasks++;
}
}
if (unfinishedTasks == 1){
//We are all done. 1 Because its the current one that hasnt finished post execute
callWhateverMethod();
}
Well as you do know when an AsyncTask ends (when onPostExecute gets called):
one solution could be to create a method setProgressBarVisible() that keeps a counter and when first called sets visible, and a method setProgressBarInvisible() that decreases the counter and when zero sets the progress bar invisible.
:-? i think it's just a trick. you will return some message at onPostExecute of each Asyntask and compare it. (this message can contain a time, for example)
A official support of CompletableFuture was introduced since API level 24.
It's also available in Java 8 here.
Can use simply use something like:
taskA.thenCombine(taskB).thenCombine(taskC)
I would simply notify it at onPostExecute(), refer to onPostExecute and 4 steps in the document for detail and you can use EventBus to do some subscribe things.
This is a common question when you want to run a bunch of AsynTasks on a THREAD_POOL_EXECUTOR. It's much more faster than if you just call .execute() and all your tasks are done one by one.
So if you have multiple jobs and objects are not depending on each other states - try to run on a thread pool.
But the question is: how do I know that all of my tasks are done?
There is no built in methods in AsyncTask so you should do a little workaround.
In my case I added a static Hashmap field to my Asynctask class to keep track of all started and finished tasks. As a bonus of a map I can always know which task is currently in progress.
private static HashMap<Uri, Boolean> mapOfAttachmentTasks = new HashMap<>();
and ad simple three methods to access this map.
Important: they should be synchronized
public static synchronized void addTask(Uri uri){
mapOfAttachmentTasks.put(uri, true);
}
public static synchronized void removeTask(Uri uri){
mapOfAttachmentTasks.remove(uri);
}
public static synchronized boolean isTasksEmpty(){
return mapOfAttachmentTasks.isEmpty();
}
You want to add a new item to the tracking Map in an AsyncTask constructor and remove it in onPostExecute():
public AttachmentTask(Uri uri) {
this.uri = uri;
addTask(uri);
}
#Override
protected void onPostExecute(Attachment attachment) {
removeTask(uri);
if(isTasksEmpty())
EventBus.getDefault().post(new AttachmentsTaskFinishedEvent(attachment));
}
Everytime a task is finished it calls onPostEexecute and you check if it was the last task. If there is no tasks left - send a signal that you're done.
Now, here I used EventBus to send event to my Fragment but you can use a callback. In this case you should create an interface with callbackMethod, your Fragment (any of your UI components which are waiting for the event) should implement this interface and have that method. Then in AsyncTask constructor you get your Fragment as an argument and keep a reference to it, so you can call it's callback method when everything is done.
But I dont like such approach. First you need to keep the reference of your Fragment (or any other UI) in a WeakReference wrapper becasue you will get a memory leak when your fragment is dead (but still kept in memory becasue your AsyncTask has it's reference).
Also you would need to make a lot of checks and it will look something like that:
private boolean isAlive() {
return mFragmentWeakReference != null
&& mFragmentWeakReference.get() != null
&& mFragmentWeakReference.get().isAdded()
&& mFragmentWeakReference.get().getActivity() != null
&& !mFragmentWeakReference.get().getActivity().isFinishing();
yep, in production you should be a little paranoic and do all these checks :)
That's why you can use EventBus and if your UI is dead - whatever.
try this, maybe can help you...
final ImageUploader _upload = new ImageUploader();
_upload.setValue(getApplicationContext(), _imagepath, _urlPHP);
_upload.execute();
Runnable _run;
Handler _h2;
_run = new Runnable() {
public void run() {
_h2 = new Handler();
_h2.postDelayed(this, 1000);
Toast.makeText(getApplicationContext(), "not finished", Toast.LENGTH_LONG).show();
if (_upload.getStatus() == AsyncTask.Status.FINISHED) {
Toast.makeText(getApplicationContext(), "finished", Toast.LENGTH_LONG).show();
_h2.removeCallbacks(_run);
}
}
};
_h2 = new Handler();
_h2.postDelayed(_run, 1);

Categories

Resources