Why AsyncTask won't start if it starts / stops repeatedly?
So I was debugging an issue in my game where if I start then stop it a few times, I noticed that sometimes Asynctask doesn't seem to start, although I seem to be doing the right thing to start this. I've removed a lot of unnecessary code to show what's going on, but basically I can see that I'm going to start Asynctask, but the task never starts.
public void onStart()
{
super.onStart();
Log.d(TAG,"About to execute");
Play_level.execute();
}
AsyncTask<Void,Integer,Integer> Play_level=new AsyncTask<Void, Integer, Integer>(){
protected void onProgressUpdate(Integer ...time) {
//Stuff goes in here.
}
@Override
protected Integer doInBackground(Void... params) {
Log.d(TAG,"In Task");
}
};
And the logarithm shows:
03-10 19:28:16.983: D/Level(1535): About to execute
03-10 19:28:17.503: D/Level(1535): onStop()
03-10 19:28:17.993: D/Level(1535): onPause()
03-10 19:28:19.174: D/AJEG(1535): Starting Tongue
03-10 19:28:19.313: D/Level(1535): ImageList Previously Loaded
03-10 19:28:19.313: D/Level(1535): About to execute
03-10 19:28:19.853: D/Level(1535): onStop()
03-10 19:28:20.283: D/Level(1535): onPause()
03-10 19:28:21.464: D/AJEG(1535): Starting Tongue
03-10 19:28:21.604: D/Level(1535): ImageList Previously Loaded
03-10 19:28:21.604: D/Level(1535): About to execute
03-10 19:28:22.134: D/Level(1535): onStop()
03-10 19:28:22.404: D/Level(1535): onPause()
03-10 19:28:23.504: D/AJEG(1535): Starting Tongue
03-10 19:28:23.644: D/Level(1535): ImageList Previously Loaded
03-10 19:28:23.644: D/Level(1535): About to execute
03-10 19:28:24.184: D/Level(1535): onStop()
Also, no amount of re-entering the task seems to be able to restart the code, as the last bit of text shows.
To give a little more context, the starting language is reproduced in the onStart () of the parent activity (AJEG), the level is the name of the activity I'm launching. The ImageList command can be safely ignored, but I've included it for completeness. The part doInBackground
includes the text "Starting level _", where _ is the level that should be started. onStop () and onPause () are in a method showing when onStop()
and are onPause()
occurring in a level task.
source to share
So, the solution to the problem is indicated in this blog article :
AsyncTask uses a static internal work queue with a hard-coded limit of 10 items
So, essentially, I had an AsyncTask that never finished until 10, re-starting my thread. To get around this, I did the following:
- I converted the AsyncTask to a class and ensured that only one instance works as swing suggested.
- I canceled the task in the onStop () command as Mike D. suggested in his comment.
- I made sure I check if ASyncTask is canceled in
doInBackground
.
The result looks something like this:
private LevelPlay Play_level;
public void onStop()
{
super.onStop();
Play_level.cancel(true);
}
public void onStart()
{
super.onStart();
Play_level=new LevelPlay();
Play_level.execute();
}
class LevelPlay extends AsyncTask<Void, Integer, Integer>
{
protected void onProgressUpdate(Integer ...time) {
}
@Override
protected Integer doInBackground(Void... params) {
Log.d(TAG,"In Task");
Boolean keepRunning=true;
while(keepRunning && !isCancelled ())
{
//DoStuffHere
}
}
}
source to share
From http://developer.android.com/reference/android/os/AsyncTask.html you notice: The task can be executed only once (an exception will be thrown if a second execution is attempted.)
.
In your application, you create a single AsyncTask and try to reuse it. Instead, create a new instance for each run.
source to share
Here is the code that works for me:
public class ImageActivity extends Activity {
private Thread worker;
public void onCreate(Bundle bundle) {
super.onCreate(bundle);
setContentView(R.layout.main);
worker = new Thread(new Runnable(){
private void updateUI(final List<Object> list)
{
if(worker.isInterrupted()){
return;
}
runOnUiThread(new Runnable(){
@Override
public void run()
{
// Update view and remove loading spinner etc...
}
});
}
private List<Object> download()
{
// Simulate download
SystemClock.sleep(1000);
return new ArrayList<Object>();
}
@Override
public void run()
{
Log.d(TAG, "Thread run()");
updateUI(download());
}
});
worker.start(); }
@Override
protected void onDestroy()
{
super.onDestroy();
worker.interrupt();
}
}
Hope it helps.
Assuming you are talking about a onStart()
method Activity
, it might be because your application was not removed from memory when you returned to it, which means your method onStart()
is probably not being called. You might want to consider using onResume()
either onRestart()
(or perhaps both), and perhaps reverse AsyncTask
the onPause()
. This also means that in the background task, you have to check if it was canceled.
See Mach's answer for why this is happening.
source to share