I have a nested fragment containing the following method:
public void onSave() {
if (getActivity() == null || view == null) return;
if (file != null && file.exists()) {
new AsyncTask<Void, Void, Void>() {
#Override
protected void onPreExecute() {
Log.d("log", "onPreExecute of save ex");
}
#Override
protected Void doInBackground(Void... params) {
Log.d("log", "doInBackground of save ex");
//DO SOMETHING
return null;
}
protected void onPostExecute(Void result) {
BaseFragment fragment = new LocalListFragment();
((LocalLauncherFragment)(LocalEditFragment.this.getParentFragment())).setFragment(fragment);
Log.d("log", "end of save ex");
};
}.execute();
} else {
showAlert();
}
}
My problem is that if I call this method for the first time, it executes until onPostExecute(). However if I go to other fragment and opens this fragment newly(by creating a new fragment object and replacing to it) then only onPreExecute() is executed. Why doesn't this asyncTask object get executed well for the second time?
Intestingly if I use executeOnExecutor() then it works fine for the second time. But why doesn't execute() work? Is AsyncTask's life tied to fragment or something?
Thanks in advance!
It sounds to me like something is hanging in the AsyncTask. In modern versions of Android AsyncTasks run on a single thread unless you specify an Executor that's multi-threaded. onPreExecute() still runs successfully because that runs on the main thread. You never see doInBackground the second time though because the single background thread is still hung from the first call. You'll need to examine the contents of LocalKeekLauncherFragment.setFragment(fragment) to see what's causing the hang.
It seems that doInBackground thread has probably crashed second time.It cannot remain stuck from first try as onPostExecute get called and this is only possible if doInBackground has returned value successfully.
Related
so I am coming across a weird problem I cant find an explaination for. I have an async task in which in its doBackground method does a wait until a certain variable is set then the "wait" is notified
private class TestAsyncTask extends AsyncTask<Void, Object, Boolean> {
#Override
protected void onPreExecute() {
Log.d("Test1");
}
#Override
protected Boolean doInBackground(Void... params) {
Log.d("Test2");
while (nextCardToPlay == null) {
wait();
}
Log.d("Test3");
}
}
Activity A:
protected void onCreate(){
a = new TestAsyncTask().execute();
}
protected void onPause(){
a.cancel()
}
So as you can see when the activity starts, the asyncTask is started. When activity is closed the asyncTask is supposed to be cancelled.
What I noticed is that if I open the activity, close it, and reopen it again then the asynctask is created and in wait mode (never cancelled). No problem. Whats confusing is that when I start the activity (while the stale asyncTask is there), then it seems a new asyncTask is started ( because the logs from OnPreExecute are called) however the doInBackground in the nextAsyncTask is not executed because the Test2 log is not showing.
Any idea why?
This behavior is not at all weird if you look at the documentation, which states the AsyncTasks run on a single background thread, i.e. sequentially. If you really want your tasks to run on parallel worker threads, then use the executeOnExecutor() method instead of a simple execute() and pass it the AsyncTask.THREAD_POOL_EXECUTOR parameter.
The goal:
Using Google App Engine server and Android client, I'm trying to put on the Google map at the Android client Users overlays. Every 30 seconds I'm polling the server and getting Vector that contains users and adding it to the map.
Current status:
I'm dong all that using in one new thread, So after running the app I got:
weird behaviors(delayed overlays, multiple overlays) and after that crushed with ConcurrentModificationException.
After reading a bit i figured out that I need to work with AsyncTask.
Correct me if I'm wrong,But I understand that everything done in the Activity at at onCreate is "running" in UIhread so I need to put the "Logic" (All the Network handling) in doInBackground and all the UI Handling like putting overlays on the map in onPostExecute.
My Question are:
1) In the current status I'm doing:
new Thread()
{
#Override
public void run()
{
super.run();
while(true)
{
SystemClock.sleep(30000);
Vector responseFromServer = getUsersVectorFromServer();
putNewOnlineUserOnTheMap();
}
}
}.start();
What is the right way to convert this To AsyncTask?
Do I poll the server still using new thread in the doInBackground or there is right way to do this?
2) Is there a specific list of what counts as UI to put in onPostExecute or any concepts list?
In my case I guess that in need to put putNewOnlineUserOnTheMap() in onPostExecute.
Thanks.
Something similar to the following:
class UpdateTask extends AsyncTask<Void, Vector, Void>{
#Override
protected Void doInBackground(Void... params) {
// this is running in a background thread.
while (!isCancelled()) {
SystemClock.sleep(30000);
Vector responseFromServer = getUsersVectorFromServer();
// send the result back to the UI thread
// onProgressUpdate will be called then
publishProgress(responseFromServer);
}
return null;
}
#Override
protected void onProgressUpdate(Vector... values) {
// this is executed on the UI thread where we can safely touch UI stuff
putNewOnlineUserOnTheMap(values[0]);
}
}
You can't use the result of the task since the task is finished then. But you can use the progress publishing mechanism to get periodic results. If you use it like that and do the modification on the UI thread you should not get ConcurrentModificationException because you do the modifications on the one thread that can safely modify the UI.
One thing to note here: create new instances of your Vector in the background thread and then use it to update the UI. But don't touch the same object afterwards in the backgroundthread. That way you don't need any synchronization since after the background thread sends it away it is only the UI thread that touches it. (and you could use a simple ArrayList instead of a Vector)
AsyncTask uses generics and varargs.The parameters that are passed to the asyntask are . TypeOfVariableArgumentsParameters is passed into the doInBackground(), ProgressParam is used for progress information and ResultParam must be returned from doInBackground() and is passed to onPostExecute() as parameter.
example:--
protected class ParsingTask extends AsyncTask> {
private ProgressDialog loadingDialog = new ProgressDialog(JsonParserActivity.this);
protected void onPreExecute() {
loadingDialog.setMessage("loading app store..");
loadingDialog.show();
}
#Override
protected ArrayList<Items> doInBackground( Context... params ) {
// do ur process here.
return result;
}
if (!this.isCancelled()) {
}
return result;
}
#Override
protected void onProgressUpdate(String... s) {
super.onProgressUpdate(s);
Toast.makeText(getApplicationContext(), s[0], Toast.LENGTH_SHORT).show();
}
#Override
protected void onPostExecute( ArrayList<Items> response ) {
//if u r dealing with list view and adapters set the adapter here at the onPostExecute()
loadingDialog.dismiss();
}
#Override
protected void onCancelled() {
super.onCancelled();
Toast.makeText(getApplicationContext(), "The operation was cancelled", 1).show();
}
}
You can use AsyncTask like below. Hope this will help you..
Class YourClass{
void YourClass(){
NetworkTask nT = new NetworkTasK();
nT.execute();
}
}
protected class NetworkTask extends AsyncTask<Void, String, Boolean>
{
#Override
protected Boolean doInBackground(Void... params)
{
try
{
String response;
while(keepreceiving)
{
response = in.readLine();//Prog Counter stops here until getting i/p.
if(response != null)
yourFunctionForResponse(response);
}
}
catch (Exception ex)
{
}
return null;
}
private void yourFunctionForResponse(String response){
//things to do....
}
}
You may also try runOnUiThread(Runnable action) along with this to implement your work.
I am using AsyncTask on button click to refresh the screen. Following is the sequence of events that happen on btn click
progress dialog shows up
The doInBackground is called and thread is initialized which calls a web service. The web service fetches/uploads data. A pass/fail flag is set once the web service is called.
My problem is the onPostExecute is never called and therefore the screen is never refreshed.
And secondly by the time the data is downloaded and the web service sets the flag my code has already hit return stmt in doInBackground.
Question is how do i stop execution in my asynctask so that the web service is done downloading/uploading the data and finally execute onPostexecute.
FYI
I also get the following warning in eclipse
The method onPostExecute(boolean) from
the type
Screen.ConnectWebService is
never used locally
private class ConnectWebService extends AsyncTask <Void, Void, Boolean>
{
private final ProgressDialog pd = new ProgressDialog(screen.this);
protected void onPreExecute() {
pd.show(Screen.this, "Sync", "Sync in progress",true,false);
}
protected Boolean doInBackground(Void... unused) {
if (SyncInProgress == false)
{
CallWSThread();//creates thread which calls web service
}
Log.d("doInBackground","doInBackground");
return SyncStatus;
}
protected Void onPostExecute(boolean result)
{
pd.dismiss();
if (result==true) drawRadioButtons();
return null;
}
}
It should be:
protected Void onPostExecute(Boolean result)
As djg noted, you have a typo in your method declaration. You can avoid these kinds of mistakes by using the annotation #Override when you're implementing methods from a super class.
This question already has answers here:
Android SDK AsyncTask doInBackground not running (subclass)
(9 answers)
Closed 9 years ago.
I'm having a problem with the AsyncTask class. It seems like my task stops working after creating 4 or 5 tasks.
Im having 2 activities. MainActivity which only holds a button that starts a second activity called ImageActivity.
ImageActivity is very simple. it got an onCreate that sets the layout, and then it starts a new AsyncTask that loads an image from the internet. This works fine the first few times. But than it suddenly stops working. The onPreExecute method is run every time, but not the doInBackground method. I have tried to simplify the doInBackground with a sleeping loop, and the same thing happens. I cant understand this behavour since the asynctask is both canceled and set to null in the onDestroy method. So every time i start a new ImageActivity, i also create a fresh AsyncTask.
I recreate the ImageActivity and the task by hitting the back button, and than clicking the button on the MainActivity.
Any ideas anyone? I'm really struggling with this one.
UPDATE: Code that starts the ImageActivity (inside a button onClickListener)
Intent intent = new Intent();
intent.addFlags(Intent.FLAG_ACTIVITY_NO_ANIMATION);
intent.setClassName(this, ImageActivity.class.getName());
startActivity(intent);
The code above starts this activity
public class ImageActivity extends Activity {
private AsyncTask<Void, Void, Void> task;
public void onCreate(Bundle bundle) {
super.onCreate(bundle);
setContentView(R.layout.main);
task = new AsyncTask<Void, Void, Void>() {
#Override
protected void onPreExecute()
{
Log.d(TAG, "onPreExecute()");
}
#Override
protected Void doInBackground(Void... params)
{
Log.d(TAG, "doInBackground() -- Here is the download");
// downloadBitmap("http://mydomain.com/image.jpg")
return null;
}
#Override
protected void onPostExecute(Void res)
{
Log.d(TAG, "onPostExecute()");
if(isCancelled()){
return;
}
}
}.execute();
}
#Override
protected void onDestroy()
{
super.onDestroy();
task.cancel(true);
}
}
UPDATE:
I have tested using a combination of traditional Threads and runOnUiThread method, and it seems to work better. Now the thread runs every time.
Removing the AsyncTask and using a traditional Thread instead of combining it with runOnUiThread seems to work. But I still have not found the reason why the AsyncTask is so "unstable".
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();
}
}
I ran into similar problem. You can't have multiple Asynctasks running in parallel up until SDK 11. Check here for more info
I just ran into this problem as well. If you use AsyncTask.execute, your task is run on a serial queue (from the Android 4.3 source):
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.
This is consistent with behavior that I saw. I had an AsyncTask popped up a dialog in doInBackground and blocked until the dialog was closed. The dialog needed its own AsyncTask to complete. The dialog's AsyncTask.doInBackground method never executed because the original AsyncTask was still blocked.
The solution is to execute the second AsyncTask in a separate Executor.
Use traceview to investigate -- or obtain a thread dump. My guess is that one of your AsyncTask threads are hanging on downloading.
AsyncTask has a small thread pool, so if one of your tasks hangs, it could end up blocking your thread pool.
Here's a quick test you can run -- on 4.3, I see that I have only 5 concurrent threads I can run. When one thread exits, other threads start up.
private void testAsyncTasks() {
for (int i = 1; i <= 10; i++) {
final int tid = i;
new AsyncTask<Integer, Void, Void>() {
protected void onPreExecute() {
Log.d("ASYNCTASK", "Pre execute for task : " + tid);
};
#Override
protected Void doInBackground(Integer... args) {
int taskid = args[0];
long started = SystemClock.elapsedRealtime();
Log.d("ASYNCTASK", "Executing task: " + taskid + " at " + started);
for (int j = 1; j <= 20; j++) {
Log.d("ASYNCTASK", " task " + taskid + ", time=" + (SystemClock.elapsedRealtime() - started));
SystemClock.sleep(1000);
}
return null;
}
protected void onPostExecute(Void result) {
Log.d("ASYNCTASK", "Post execute for task : " + tid);
};
}.execute(i);
}
}
You shouldn't have to worry about housekeeping thread in Android as it is managed by the system.
Please also post the image download method. Have you also tried to not cancel the thread in the onDestroy() method? How are you returning the the image to your UI thread?
The problem I believe is with the heavy image download task. Even if you cancel the async task the image download will continue to execute and the async task does not finish until the download is complete. You might want to check the isCancelled() method on AyncTask while the download is going on and kill the download if the task is cancelled.
For reference, heres the documentation on cancel() method :
Attempts to cancel execution of this task. This attempt will fail if the task has already completed, already been cancelled, or could not be cancelled for some other reason. If successful, and this task has not started when cancel is called, this task should never run. If the task has already started, then the mayInterruptIfRunning parameter determines whether the thread executing this task should be interrupted in an attempt to stop the task.
Calling this method will result in onCancelled(Object) being invoked on the UI thread after doInBackground(Object[]) returns. Calling this method guarantees that onPostExecute(Object) is never invoked. After invoking this method, you should check the value returned by isCancelled() periodically from doInBackground(Object[]) to finish the task as early as possible.
I had this too, no real reason for not starting. I've noticed that after restarting adb it worked again. Not sure why this is, but it did work for me
In my application I use an AsyncTask on start up of my Activity to fetch the ringtone of a particular contact.
It works normally but I have noticed that if the application is stopped twice before the AsyncTask gets to the doInBackground method then when the Activity starts again the AsyncTask fails to run properly, only getting to the onPreExecute() method.
Here is my code:
The AsyncTask itself:
private class SelectRingtoneTask extends AsyncTask<String, Void, Void> {
// can use UI thread here
protected void onPreExecute() {
Log.d("cda", "Into selectRingToneTask - onPreExecute() - " + selectRingtoneFinished);
}
// automatically done on worker thread (separate from UI thread)
protected Void doInBackground(final String... args) {
Log.d("cda", "Into selectRingToneTask - !!!!!!!!!!!!!!!");
getRingTone();
return null;
}
// can use UI thread here
protected void onPostExecute(final Void unused) {
selectRingtoneFinished = true;
Log.d("cda", "Into selectRingToneTask - onPostExecute - " + selectRingtoneFinished);
}
}
Where I call the AsyncTask on start up:
if(srtt == null){
srtt = new SelectRingtoneTask();
Log.d("cda", "RingTone - " + srtt.getStatus());
}
srtt.execute();
The problem occur's when I start the activity and close the Activity before the AsyncTask finishes, if this happens once, it seems to be fine but after it happens a second time the AsyncTask will only ever get to the onPreExecute() method and will never complete again until the application is force stopped and restarted.
Has anybody got any idea why this would be happening?
You need to cancel the AsyncTask when your Activity is destroyed, and in AsyncTask's methods check for isCancelled flag before attempting to work with the fetched results.
I highly recommend reading the source code of Shelves to see how to persist tasks across configuration changes and how to cancel them properly when the activity is destroyed.
if(srtt == null){ <--- Not needed
srtt = new SelectRingtoneTask();
Log.d("cda", "RingTone - " + srtt.getStatus());
}
srtt.execute();
Im not sure what do you meen by close, but I had similar problem with thread.
In my opinion problem here is that you fire second time this same activetask, when you are not allowed to do. to sole the problem when you close activity, cancel thread and make sure you set srtt to null. Hope this helps