I've looked at other questions and I failed to clarify my doubt as to call a task from another task, I have the following code:
protected List<Plan> doInBackground(String... params)
try {
JSONParsePlans parseJSON = new JSONParsePlans();
return parseJSON.execute(params[0], params[1], params[2]).get();
} catch (InterruptedException e) {
e.printStackTrace();
return null;
} catch (ExecutionExeption e) {
e.printStackTrace();
return null;
}
}
parseJSON is a task, when I run the program does nothing, not even called to task, it's like what Android omitted for security.
According to this StackOverflow Post:
but only inside onProgressUpdate() or onPostExecute() since these methods runs on the UI thread. Therefore, start the second AsyncTask on the UI thread by choosing one of the two methods listed above.
So you can call an AsyncTask from another AsyncTask, so long as it runs in either of those two methods.
There is also another StackOverflow post that addresses this issue here
It is possible to call an Async Task from another Async Task
but only inside onProgressUpdate() or onPostExecute()
Reason - since these methods runs on the UI thread. Therefore, start the second AsyncTask on the UI thread by choosing one of the two methods listed above.
Related
I want to update my UI from a Thread which updates a Progressbar. Unfortunately, when updating the progressbar's drawable from the "runnable" the progressbar disappears!
Changing the progressbars's drawable in onCreate() on the otherside works!
Any Suggestions?
public void onCreate(Bundle savedInstanceState) {
res = getResources();
super.onCreate(savedInstanceState);
setContentView(R.layout.gameone);
pB.setProgressDrawable(getResources().getDrawable(R.drawable.green)); //**Works**/
handler.postDelayed(runnable, 1);
}
private Runnable runnable = new Runnable() {
public void run() {
runOnUiThread(new Runnable() {
public void run()
{
//* The Complete ProgressBar does not appear**/
pB.setProgressDrawable(getResources().getDrawable(R.drawable.green));
}
});
}
}
You should do this with the help of AsyncTask (an intelligent backround thread) and ProgressDialog
AsyncTask enables proper and easy use of the UI thread. This class allows to perform background operations and publish results on the UI thread without having to manipulate threads and/or handlers.
An asynchronous task is defined by a computation that runs on a background thread and whose result is published on the UI thread. An asynchronous task is defined by 3 generic types, called Params, Progress and Result, and 4 steps, called begin, doInBackground, processProgress and end.
The 4 steps
When an asynchronous task is executed, the task goes through 4 steps:
onPreExecute(), invoked on the UI thread immediately after the task is executed. This step is normally used to setup the task, for instance by showing a progress bar in the user interface.
doInBackground(Params...), invoked on the background thread immediately after onPreExecute() finishes executing. This step is used to perform background computation that can take a long time. The parameters of the asynchronous task are passed to this step. The result of the computation must be returned by this step and will be passed back to the last step. This step can also use publishProgress(Progress...) to publish one or more units of progress. These values are published on the UI thread, in the onProgressUpdate(Progress...) step.
onProgressUpdate(Progress...), invoked on the UI thread after a call to publishProgress(Progress...). The timing of the execution is undefined. This method is used to display any form of progress in the user interface while the background computation is still executing. For instance, it can be used to animate a progress bar or show logs in a text field.
onPostExecute(Result), invoked on the UI thread after the background computation finishes. The result of the background computation is passed to this step as a parameter.
Threading rules
There are a few threading rules that must be followed for this class to work properly:
The task instance must be created on the UI thread.
execute(Params...) must be invoked on the UI thread.
Do not call onPreExecute(), onPostExecute(Result), doInBackground(Params...), onProgressUpdate(Progress...) manually.
The task can be executed only once (an exception will be thrown if a second execution is attempted.)
Example code
What the adapter does in this example is not important, more important to understand that you need to use AsyncTask to display a dialog for the progress.
private class PrepareAdapter1 extends AsyncTask<Void,Void,ContactsListCursorAdapter > {
ProgressDialog dialog;
#Override
protected void onPreExecute() {
dialog = new ProgressDialog(viewContacts.this);
dialog.setMessage(getString(R.string.please_wait_while_loading));
dialog.setIndeterminate(true);
dialog.setCancelable(false);
dialog.show();
}
/* (non-Javadoc)
* #see android.os.AsyncTask#doInBackground(Params[])
*/
#Override
protected ContactsListCursorAdapter doInBackground(Void... params) {
cur1 = objItem.getContacts();
startManagingCursor(cur1);
adapter1 = new ContactsListCursorAdapter (viewContacts.this,
R.layout.contact_for_listitem, cur1, new String[] {}, new int[] {});
return adapter1;
}
protected void onPostExecute(ContactsListCursorAdapter result) {
list.setAdapter(result);
dialog.dismiss();
}
}
The most simplest solution I have seen to supply a short
execution to the UI thread is via the post() method of a view.
This is needed since UI methods are not re-entrant. The
method for this is:
package android.view;
public class View;
public boolean post(Runnable action);
The post() method corresponds to the SwingUtilities.invokeLater().
Unfortunately I didn't find something simple that corresponds to
the SwingUtilities.invokeAndWait(), but one can build the later
based on the former with a monitor and a flag.
So what you save by this is creating a handler. You simply need
to find your view and then post on it. You can find your view via
findViewById() if you tend to work with id-ed resources. The resulting
code is very simple:
/* inside your non-UI thread */
view.post(new Runnable() {
public void run() {
/* the desired UI update */
}
});
}
Note: Compared to SwingUtilities.invokeLater() the method
View.post() does return a boolean, indicating whether the
view has an associated event queue. Since I used the
invokeLater() resp. post() anyway only for fire and forget,
I did not check the result value. Basically you should
call post() only after onAttachedToWindow() has been called
on the view.
Best Regards
If you use Handler (I see you do and hopefully you created its instance on the UI thread), then don't use runOnUiThread() inside of your runnable. runOnUiThread() is used when you do smth from a non-UI thread, however Handler will already execute your runnable on UI thread.
Try to do smth like this:
private Handler mHandler = new Handler();
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.gameone);
res = getResources();
// pB.setProgressDrawable(getResources().getDrawable(R.drawable.green)); **//Works**
mHandler.postDelayed(runnable, 1);
}
private Runnable runnable = new Runnable() {
public void run() {
pB.setProgressDrawable(getResources().getDrawable(R.drawable.green));
pB.invalidate(); // maybe this will even not needed - try to comment out
}
};
Use the AsyncTask class (instead of Runnable). It has a method called onProgressUpdate which can affect the UI (it's invoked in the UI thread).
You need to create a Handler in the UI thread and then use it to post or send a message from your other thread to update the UI
If you don't like the AsyncTask you could use the observer pattern. In that example use the ResponseHandler as an inner class in your activity then have a string message that will set the progress bars percentage... You would need to make sure that any alterations to the UI are performed within the ResponseHandler to avoid freezing up the UI, then your worker thread (EventSource in the example) can perform the tasks required.
I would use the AsyncTask tho, however the observer pattern can be good for customization reasons, plus its easier to understand. Also im not sure if this way is widely accepted or will 100% work. Im downloading and the android plugin now to test it
As recommended by official documentation, you can use AsyncTask to handle work items shorter than 5ms in duration. If your task take more time, lookout for other alternatives.
HandlerThread is one alternative to Thread or AsyncTask. If you need to update UI from HandlerThread, post a message on UI Thread Looper and UI Thread Handler can handle UI updates.
Example code:
Android: Toast in a thread
I'm creating an android app which has single activity for now. This activity calls an api to get JSON response and populate the Fragments. Once the JSON response is received I am updating the data set and notifying adapter. Currently the JSON request is called in onCreate method.
Similarly in each fragment I need to load image from network so I am wondering will it too should be put in onCreateView or someplace else?
I'm interested in knowing what is the best practice to achieve this.
The best practise is to use an asynchronous event when doing networking stuff, because depending on your server response time andd on your network speed, you will maybe get the response late and that block your UI and that's not good.
I suggest you integrate AsyncTask when calling your API.
Here is an example
class JSONAsyncTask extends AsyncTask<String, Void, Boolean> {
#Override
protected void onPreExecute() {
super.onPreExecute();
}
#Override
protected Boolean doInBackground(String... urls) {
try {
//here you make your api call and json parsing
} catch (IOException e) {
e.printStackTrace();
} catch (JSONException e) {
e.printStackTrace();
}
return false;
}
protected void onPostExecute(Boolean result) {
}
And you call your request in your onCreate like this
JSONAsyncTask task=new JSONAsyncTask();
task.execute();
Take a look at docs for further information https://developer.android.com/reference/android/os/AsyncTask
It's fine doing network call in onCreate, put my two cents in i suggest you this good practices that i use.
-Study network call and try to estabilish how many time it takes and if result is needed for UI thread, For long operations AsyncTask should not be used
From documentation
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.
-Never reinvent the wheel you could use a lot of libray for network operations like:
Retrofit
OkHttp
Volley
AndroidFastNetworking
-Always handle error! There is nothing more annoying than an infinite loader caused by some connection error, check internet connection with BroadCast Receiver
In android there is the AsyncTask which runs a thread and then i can use the method on post execute to interact with main thread again. is there an equivalent to this in java? i am trying to run a timer on separate thread (doInBackground) and once the time is finished it will then allow me to interact with the main theard to restart a service (onPostExecute will restart service)
I'm not Android developer but I think it could be easily implemented by using a CompletableFuture on Java 8:
import java.lang.reflect.InvocationTargetException;
import java.util.concurrent.CompletableFuture;
import javax.swing.SwingUtilities;
public abstract class AsyncTask <Params, Progress, Result> {
protected AsyncTask() {
}
protected abstract void onPreExecute();
protected abstract Result doInBackground(Params... params) ;
protected abstract void onProgressUpdate(Progress... progress) ;
protected abstract void onPostExecute(Result result) ;
final void publishProgress(Progress... values) {
SwingUtilities.invokeLater(() -> this.onProgressUpdate(values) );
}
final AsyncTask<Params, Progress, Result> execute(Params... params) {
// Invoke pre execute
try {
SwingUtilities.invokeAndWait( this::onPreExecute );
} catch (InvocationTargetException|InterruptedException e){
e.printStackTrace();
}
// Invoke doInBackground
CompletableFuture<Result> cf = CompletableFuture.supplyAsync( () -> doInBackground(params) );
// Invoke post execute
cf.thenAccept(this::onPostExecute);
return this;
}
}
Solution Tailored for You
In short, look at java: run a function after a specific number of seconds.
For your purpose, you don't need an AsyncTask. AsyncTask is for running something that needs the time, but you would prefer it didn't (e.g. a complex calculation or fetching data from the internet). It's for getting around the problem that you would need to wait.
What you want to do instead is to introduce a delay, or more precisely you want to schedule some action to happen after a delay. You can use a class like AsyncTask for this as well, but it's an overkill and results in more complicated code. You should instead use a class which is tailored for delayed execution, which is Timer and TimerTask:
new java.util.Timer().schedule(
new java.util.TimerTask() {
#Override
public void run() {
// your code here
}
},
5000
);
Equivalent of AsyncTask in standard Java
Note that AsyncTask is connected to a UI concept (UI = user interface), because it may only be started from the UI thread. It's not for generally running something asynchronously.
Thus, the best matching equivalent of android's AsyncTask is SwingWorker in Java. Swing is Java's standard UI framework. It has a similar concept as android with a UI thread. In Swing, this thread is called the Event Dispatch Thread. Hence, the design of SwingWorker is also very similar to AsyncTask. Even the doInBackground() method has the same name in both classes.
Asynchronous Execution in General
If your requirement is not related to a UI and you only want to source some time consuming operation out so it executes asynchronously, then you need to look at executors. There is a variety of different ways to use executors for many different purposes, so this would go beyond the scope of this answer. If you are interested in further information, start with Jakob Jenkov's tutorial on ExecutorService.
In Java, I've gotten used to working with Futures. Now I'm looking at Android, and AsyncTask implements almost all the same methods and covers similar lifecycles. But, if I want to be consistent and use Future all over my code, I have to wrap AsyncTask in a stupid wrapper, cause it doesn't actually implement Future.
All they'd need to add is an isDone() method, which seems like it would be trivial, then add implements Future<Result>. (added later: see my answer below for just how trivial it would be).
Any Android experts know some good reason / obscure bug it might cause why this hasn't been done?
From reading the actual code of AsyncTask.java it actually uses a Future task and then some more. A Future is a task that executes asynchronously on the go. An AsyncTask is scheduled on a queue for a single (or pool of) background thread(s).
An AsyncTask is actually more "superior" than a Future task. It does fancy scheduling and optimizations on top of Future's functionality. Just look at the API introduction levels. Future was introduced right from the start API 1.0. The AsyncTask object was introduced in API 3.
An AsyncTask has-a Future task, not is-a Future.
AsyncTask.java
/**
* Creates a new asynchronous task. This constructor must be invoked on the UI thread.
*/
public AsyncTask() {
mWorker = new WorkerRunnable<Params, Result>() {
public Result call() throws Exception {
mTaskInvoked.set(true);
Process.setThreadPriority(Process.THREAD_PRIORITY_BACKGROUND);
//noinspection unchecked
return postResult(doInBackground(mParams));
}
};
mFuture = new FutureTask<Result>(mWorker) {
#Override
protected void done() {
try {
postResultIfNotInvoked(get());
} catch (InterruptedException e) {
android.util.Log.w(LOG_TAG, e);
} catch (ExecutionException e) {
throw new RuntimeException("An error occured while executing doInBackground()",
e.getCause());
} catch (CancellationException e) {
postResultIfNotInvoked(null);
}
}
};
}
I'm still interested in the theoretical reasons "why" not to use AsyncTask for a Future.
But, for the record, I ended up creating my own little class (shown below). Just extend it instead of AsyncTask if you want a Future. IMO, a cleaner way than the #Eng.Fouad idea of accessing the private mFuture within the code. (But thanks for the idea, it got me looking into the source code a bit!) YMMV.
public abstract class FutureAsyncTask<Params, Progress, Result> extends AsyncTask<Params, Progress, Result> implements Future<Result>{
#Override
public boolean isDone() {
return AsyncTask.Status.FINISHED == getStatus();
}
}
AsyncTask is too simple. It's intended for short tasks which may take a few seconds, but for which you don't want to lock up the UI thread. If you actually need a Future, your task is probably too complex for an AsyncTask anyway.
You can check the status of an AsyncTask by calling getStatus(). This will return an enum which can be one of Status.PENDING, Status.RUNNING or Status.FINISHED.
I am pulling around 1500 data plots and adding them to overlays for an map view. I want to run this in another thread while the rest of my program finishes starting up. I would like a progress spinner to spin only on the map portion while its loading the data plot points.
I have searched and found what I need, but Im not sure how to implement it and where in my code to put it.
What would I put in the params
Does this go in another class or in my main oncreate method.
When would I call the methods?
private class UpdateFeedTask extends AsyncTask<MyActivity, Void, Void> {
private ProgressDialog mDialog;
protected void onPreExecute() {
Log.d(TAG, " pre execute async");
mDialog = ProgressDialog.show(MyActivity.this,"Please wait...", "Retrieving data ...", true);
}
protected void onProgressUpdate(Void... progress) {
Log.d(TAG, " progress async");
}
#Override
protected Void doInBackground(MyActivity... params) {
// TODO Auto-generated method stub
return null;
}
protected void onPostExecute(Void result) {
Log.d(TAG, " post execute async");
mDialog.dismiss();
}
}
From your question I actually am not a hundred percent sure what you currently understand about AsyncTasks so this may be a little some stuff you already know but bear with me.
"Does this go in another task or in my onCreate method?":
AsyncTask is a class which you are supposed to subclass to do what you need, it is not a piece of code which can inlined in your onCreate. You could make an anonymous AsyncTask class in your onCreate, but usually you want it as either a private internal class or its own class entirely.
As for when you call the methods; you don't they are lifecycle events.
onPreExecute() is called on the UI thread just before starting the background work and is a place to do things such as modify components to show progress, or throw up a dialog.
doInBackground(Params...) is the main method which runs in the background on another thread, do your work here. Do not try to modify UI here
onPostExecute(Result) is when your task has finished and is run on the UI thread again. This is where you should handle your UI update.
You only call execute(Params..), which will start the AsyncTask, passing the objects you put as the params into the doInBackground(Params...) method of the task. So the answer as to what to put as params is whatever you need to have access to in doInBackground(Params...).
That should be a decent overview for your needs but you should really check out the docs.
To start the AsyncTask, you simply go
(new UpdateFeedTask()).execute(activityInstance);
It can go where ever you want it, though where you put it might limit access to the variables and objects you want to interact with. E.g. private internal class will have access to them while an entirely new class might not have as easy of an access.
doInBackground(MyActivity... params)
is where the parameter you passed into the execute() function will go, and you can access it via params[0].
You should not call any methods in the AsyncTask class, besides execute().
1. What would I put in the params
It depends. The First parameter is what the task will take in.
The last generic is what it will return.
2.Does this go in another class or in my main oncreate method. You call the execute method when the you want the task to run. The implementation can be in the Activity class or in a different .java file.
3.When would I call the methods?
You only call the execute method. That will make the task run in the background. Then the task will call onPostExecute when it is done.
Here is an example
private class UpdateFeedTask extends AsyncTask<String, Void, DataReturnType> {
#Override
protected DataReturnType doInBackground(String... params) {
String url = params[0];
//Get data from URL
}
#Override
protected void onPostExecute(ReturnDataType result) {
//Do something with result
}
}
Then call the task using the execute("http://foo.com")
Also add android:configChanges=true to the Activity in the manifest. This will make sure that the activity is not killed when the task is still running in the background. Otherwise the task will finish and report back to a null Activity unless you tell the task to callback the new activity.