I have three AsyncTasks in my Splash screen Activity that downloads app data for caching. I don't want to actually start the next Activity until all task's finish.
Is there an effective way of doing this?
Here is how I call my Tasks in the onCreate:
TrendingTask task = new TrendingTask(SplashActivity.this);
task.execute();
TrendingWatchingTask task2 = new TrendingWatchingTask(
SplashActivity.this);
task2.execute();
new MasterTask().execute();
They are all called, one after the other. I don't actually start the next Activity until it gets to the onPostExecute() in MasterTask. But I believe this is a gamble cause the other two may not be finished.
Note: MasterTask is an inner class while the other two are their own classes.
You can keep a global integer counter and increment it every time an AsyncTask starts(in its onPreExecute()) and decrement it in onPostExecute(). And when you launch your activity you can check if this counter is equal to zero. If it isn't - then you know you've got AsyncTasks running.
Related
i'm fairly new to android programming. I have a main activity that gets data from a DB through a service handler (url). I want to insert data as well, but on a different activity, and i want my main activity to be up to date each time its been called (onresume(),onrestart()).
I've found this on the Android API reference about AsyncTask:
The task can be executed only once (an exception will be thrown if a second execution is attempted.)
Does that mean that i cannot call the AsyncTask whenever the activity resumes, or that i cannot have multiple "instances" of the AsyncTask running at the same time?
It literally means, that while AsyncTask is running, you cannot launch it again.
In your MainActivity.class you have line:
task.execute();
if task either is finished or not and you call the method again then exception will be thrown.
And put this method in onResume() is a good practice.
Only one thing to notice is: if you put in onRestart() remember, this callback works when you change configuration, but it will not be called if you Create activity.
The doc about lifecycle of an Activity.
Does that mean that i cannot call the AsyncTask whenever the activity resumes, or that i cannot have multiple "instances" of the AsyncTask running at the same time?
It means you cannot call the execute method twice on the same AsyncTask instance regardless it is completed or not.
My android application has 2 activities:
In the first one (MainActivity), the user chooses some parameters and these parameters are sent to the second activity (Display).
The second activity calls a web service, and according to the chosen parameters, the web service returns a value. I use the returned value to draw a bar chart of the evolution of this value. That's why I created a timer in the second activity that I put in the onCreate() function:
Timer t = new Timer();
t.scheduleAtFixedRate(new TimerTask() {
public void run() {
finish();
startActivity(getIntent());
}
},10000, 10000);
So every 10 seconds, the second activity is called again and the bar chart is updated with the new returned value.
The problem is, after the 2nd or the 3rd execution of the timer, several identical values are returned at the same time, as if the activity was called several times. And then the application starts freezing (but doesn't close).
I'm using the charts provided by this library: http://android-graphview.org/
I've also tried using the functions provided on the above website (resetData and appendData), and also the invalidate() function, but nothing works.
Any ideas why this happens? Is my way of refreshing the activity wrong?
The way you described it:
you create a new Timer (see 2.) with every call of the second activity
The purpose of each Timer is to call the second activity (see 1.) every 10 seconds
As a result the amount of times the second activity is called as a function of time increases exponentially.
A possible solution would be to move the timer to the onCreate method of your Main Activity (and still call the second activity from it).
This way there should be exactly one Timer active at any time.
EDIT:
As commented by Marius, an Activity might not be the optimal choice. If there is no user-input and the only thing the activity does is call a webservice and return the result, a method called from your Main Activity would be sufficient.
Firstly, calling finish() and starting the activity, NOT A GOOD IDEA.
Secondly, As far as i have understood your scenario, calling an AsyncTask inside a Timer after every 10 seconds is a better way to accomplish this. Call your web service in doInBackground() and then update your UI from onPostExecute(), this way you can avoid calling finish() and relaunching your activity every 10 seconds.
Finally you are creating a new Timer instance eveytime your Activity is called, so creating a huge number of Timer instances hanging your application.
Android Asynctask Generally Understanding Questions.
If I want to make Asynctask SyncTask, how do I do that?
AsyncTask A = new AsyncTask();
AsyncTask B = new AsyncTask();
A.execute();
B.execute();
If I want A to finish before B starts how should I do that?
If I close an Activity, does the AsyncTask call on that activity gets destroy?
If I close the whole application, does the AsyncTask call on that application gets destroy?
call b.execute() in onPostExecute() of A
AsyncTask is an abstract class so you must extend it in order to add your app specific functionality to it. You implement the doInBackground() method to do what ever work is required. The AsyncTask documentation explains it in detail. I will give a brief answer to each of your question.
If I want to make Asynctask SyncTask, how do I do that?
You have the right idea with creating the async task, however as I mentioned before you have to subclass the async task to actually do some work.
Here is an example (note that the Void types do have meaning however the documentation covers them in great detail)
public class MyTask extends AsyncTask<Void, Void, Void>
{
//This method will run on the back ground thread
#Override
protected Void doInBackground(Void... params)
{
// All the heavy work should be done here e.g.
// loading from network, database etc.
return null;
}
}
Then in your activity you would create and run this task as follows :
MyTask myTask = new MyTask();
myTask.execute()
If I want A to finish before B starts how should I do that?
As the documentation states:
When first introduced, AsyncTasks were executed serially on a single
background thread. Starting with DONUT, this was changed to a pool of
threads allowing multiple tasks to operate in parallel. Starting with
HONEYCOMB, tasks are executed on a single thread to avoid common
application errors caused by parallel execution.
Which means if you are using honeycomb or later async tasks will run on a single thread. So normally A should get executed before B if you execute in that order. But I would do something like this: Launch A, then when onPostExecute() of A gets called, you know that A is done, you can start your task B from this method to be sure that A finishes before B.
If I close an Activity, does the AsyncTask call on that activity gets
destroy?
The short answer to this question is No. The async task will continue to run even if the activity has called on destroy. However if the async task is tied to the activity life cycle you need to make sure you end the task when the activity dies or you will run into problems.
If I close the whole application, does the AsyncTask call on that
application gets destroy?
I am not 100% sure about this one. I believe the behavior is unspecified since now its up to Android to collect resources. It may decide to kill the task right away if its low on resources or it may not. However you should avoid this design. If you need to run something after your application has closed, then look at the Service class.
Take a look at http://www.compiletimeerror.com/2013/01/why-and-how-to-use-asynctask.html#.VNtB1LDF_38 it may help you.
I got an activity which should do 2 different things in parallel act as SplashScreen Activity:
wait for 1.5 seconds to display app splash screen
copy some files from assets to device storage in background
Activity implement initial delay (task1) by a handler and file copy (task2) by AsyncTask
Problem: delay of this activity should be such that which both task complete and then start next activity.
I should note that these two task are running in parallel in background and time of copying files may differ each time (some times longer than 1.5seconds, some times shorter).
In other word starting next activity must be synchronized by finishing of both background tasks.
So, How this can be implemented?
I think the easiest thing to do is in the beginning of your async task, get the current time. When you're done with the work, get the current time again. If this is less than 1.5 secs, then do a Thread.Sleep() for the difference.
Start the next activity in the postExecute(). Something like this:
private class DoStuffAsync extends AsyncTask<Void, Integer, Long> {
protected Long doInBackground() {
long start = new Date().getTime();
// copy assents
long end = new Date().getTime();
if ( end-start < 1500 )
Thread.sleep( 1500-(end-start));
return totalSize;
}
protected void onPostExecute(Long result) {
startActivity( new Intent(Activity.this, NewActivity.class));
}
}
Updated: Fixed math problems.
Your design is solid. The detail that you're after to sync the handler and AsyncTask chimes from the realization that both will be executed from the UI thread and therefore you don't need to worry about any concurrency issues. The easiest way then to check whether your new Activity should be started, would be to create two boolean flags. One for the 1.5s timer and the other for the file copy task. Then when either process finished, it checks whether the other flag is set to complete, and if it is, a new Activity will be launched, otherwise the completed task will set it's completed flag to true and when the remaining task completes it will launch the Activity.
I have an activity that displays a number. The number is obtained from SharedPreferences e.g
int num=pref.getInt(myAsyncTask.MYNUMBER,0);
The SharedPreference is loaded inside an AsyncTask where calculations take place (that involve retrieving data from db and so on). So, OnCreate() of the activity I run the Asynctask to calculate the value. However, the value is not always updated to the latest one when I launch the activity. This might be because Asynctask takes more time to calculate the new value than the the action of displaying the value inside the activity. How can I delay the execution of the method displaying the value until the Asynctask finishes with the process of the new one?
[[EDIT]]
I removed sharedpreferences. I use the onPostExecute() method to get the result. However, the behaviour is similar. The result is returned after the value is displayed so i couldn't see anything at all.
If the calculation doesn't take more than few second, the simplest solution is to use AsyncTask.get(), this method will block UI thread execution and make UI thread waiting for AsyncTask to finish:
public void onCreate(Bundle savedInstanceState) {
... ...
MyAsyncTask myAsyncTask = nee MyAsyncTask();
myAsyncTask.execute();
myAsyncTask.get(); // alternatively you can use AsyncTask.(long timeout, TimeUnit unit)
... ...
}
Bear in mind that it blocks UI thrread execution, if your calculation is longer than 5 seconds, you will probably get ANR exception.
Since you already use AsyncTask, a more reasonable solution is moving execution of the method displaying the value into AsyncTask.onPostExecute(), this is the exactly reason why AsyncTask exist in API to solve this kind if scenario.
Just use listener concept, or just 'pass' your Activity to your asynctask so It can call the main thread.
If the value is not showing as correct at the time you launch the activity you should set the visibility of the View to View.GONE so it doesn't appear, then change the visibility back to visible when you have the result. To update the value you could implement a listener on your activity that gets called by the AsyncTask.
If its going to take a significant time (more than a few seconds) you might want to also use a progress dialog so the user understands that they need to wait.