I have two AsyncTasks that I am using, one is called up after a dialog returns in the FragmentActivity and there is code after the .execute I call. The other .execute is called just in an if...else. The one called after another dialog returns, does what it is supposed to, it executes, on post execute it pops back the activity to the previous one and everything works.
The other the onPostExecute is never called. I did a break point in the doInBackground which executes and returns the null, just like the other one does but the onPostExecute never happens, is there some issue with having too many AsyncTasks in one FragementActivity, or too many calls to execute? I am stuck and hoping its something stupid I am just not seeing, so I am posting the code but I really cannot figure out why the onPostExecute never gets called in the AddEventWorker but does in the AddEventFromDialogWorker. The way I test the application it does so happen the AddEventFromDialogWorker gets called, works, and then anything to the AddEventWorker does not work (does do the doInBackground but not the onPostExecute).
Any ideas or avenues for me to try?
private class AddEventWorker extends AsyncTask<Void, Void, Void>{
protected void onPostExecute() {
getFragmentManager().popBackStack();
}
#Override
protected Void doInBackground(Void... params) {
mGoogleApi.addEvent(mSession, allGoogleAccounts.get(0).getGoogleCalendarName());
return null;
}
}
private class AddEventFromDialogWorker extends AsyncTask<String, Void, Void>{
protected void onPostExecute() {
Toast.makeText(mContext, "Event added to google calendar!", Toast.LENGTH_SHORT);
getFragmentManager().popBackStack();
}
#Override
protected Void doInBackground(String... params) {
mGoogleApi.addEvent(mSession, params[0]);
return null;
}
}
Your onPostExecute() method is never invoked because you are not overriding the base class' onPostExecute() method. The signature should be protected void onPostExecute(Void result). If you used #Override the compiler would have told you about this issue :)
Related
Suppose I've an AsyncTask like this :
public class MyAsyncTask extends AsyncTask<Void,Void,Boolean>{
#Override
protected Boolean doInBackground(Void... voids){
// Do some stuff
return true;
}
#Override
protected Void onPostExecute(Boolean b){
// Do Some UI Changes
}
}
But instead of calling myAsyncTask().execute() if I call myAsyncTask().execute().get() ,
For example :-
boolean b = new MyAsyncTask().execute.get();
Will the UI changes defined in onPostExecute() method still be applied? In other words does the onPostExecute() method will still be called?
Post execute got called even you called get on async task
I want to show some message and a progress bar while my app initializes.
I need to insert some dictionaries of words into a SQLite database the first time my app is run. To do this I have an AsyncTask which opens my SQLiteOpenHelper and closes it again, just so the database initialization is done once.
private class AsyncDbInit extends AsyncTask<Void, Void, Void> {
private Context context;
private Intent intent;
public AsyncDbInit(Context context, Intent intent){
this.context = context;
this.intent = intent;
}
#Override
protected Void doInBackground(Void... params) {
DatabaseHandler db = new DatabaseHandler(this.context);
db.close();
return null;
}
#Override
protected void onPostExecute(Void param) {
context.startActivity(this.intent);
}
#Override
protected void onPreExecute() {}
#Override
protected void onProgressUpdate(Void... params) {}
}
This AsyncTask is called in my onCreate() method, but I've also tried to run it from onStart() and onResume() without succes.
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_dispatcher);
... //some code finding the right intent
new AsyncDbInit(this, nextIntent).execute();
}
Somehow this last line, which calls the AsyncTask, stops my UI from showing up; the screen just stays blank until the AsyncTask is completed and the new activity is started.
When I comment that line out, the UI shows up just fine.
The only thing I can come up with is that the SQLiteOpenHelper somehow blocks the UiThread, but I couldn't find anything about that either.
In the AsyncTask we have some methods. Just like in doInBackground() we do the things we wants to be done in the background and there are two methods also whch are onPreExecute() and onPostExecute(). Create and progress dialog and show the dialog in onPreExecute() method and dismiss it in onPostExecute() method.
Try using AsynTask.executeOnExecutor() with the thread pool executor. If this works, it means something involved with loading your UI is also using an AsyncTask. AsyncTasks by default run sequentially on a single work thread and this can introduce contention. This serial execution is often what you want, but not always.
Does you UI use any libraries to load strings or other content? Can you provide your layout XML?
I'm not quite sure how to debug the phenomenon I'm currently seeing in my Android application.
I have an Activity which is just doing some networking stuff (which needs to be done in background).
This activity is launched from a PreferencesFragment using an Intent.
When the user selects the preference item, the Intent is fired and the Activity is started (then it does the networking stuff and quits using finish()).
I created an AsyncTask to perform the networking actions in the background.
(I thought that onCreate will most probably run in the UI thread...)
But then, an exception occurred:
java.lang.RuntimeException: Can't create handler inside thread that has not called Looper.prepare()
Did onCreate() already run in the background???
To test that, I moved the networking functions directly into onCreate().
This was working well...
... at least several times.
Suddenly, an exception was thrown:
java.lang.RuntimeException: Unable to start activity ComponentInfo{...}: android.os.NetworkOnMainThreadException
Moving the code back to the AsyncTask helped... for some time.
Does anyone know why this phenomenon might occur?
Are there scenarios when onCreate() runs in the UI thread and others when onCreate() runs in background?
My class is as simple as this:
public class ReregisterInDb extends Activity {
#Override
protected void onCreate(Bundle savedInstanceState) {
new ReregisterAsyncTask().execute(""); // solution 1
// solution 2
//GCMFunctions gcmFunctions = new GCMFunctions(getApplicationContext());
//gcmFunctions.registerInDb();
super.onCreate(savedInstanceState);
finish();
}
class ReregisterAsyncTask extends AsyncTask<String, Void, Void> {
#Override
protected Void doInBackground(String... params) {
GCMFunctions gcmFunctions = new GCMFunctions(getApplicationContext());
gcmFunctions.registerInDb();
return null;
}
}
}
try to move the call of the method finish() of the activity in the method onPostExecute of async task
You can't do anything before calling super.onCreate(...) put that right at the beginning as I've shown below. EDIT: Also, your use of getApplicationContext in the AsyncTask is likely causing an issue, try creating a global Context variable and initializing that in onCreate and see if that works.
Context mContext;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
mContext = this;
new ReregisterAsyncTask().execute(""); // solution 1
finish();
}
class ReregisterAsyncTask extends AsyncTask<String, Void, Void> {
#Override
protected Void doInBackground(String... params) {
GCMFunctions gcmFunctions = new GCMFunctions(mContext);
gcmFunctions.registerInDb();
return null;
}
}
I finally found out the reason for this strange behavior.
I did not post the contents of the registerInDb() method.
In that method, there is a Toast:
Toast.makeText(context,
"Not currently registered with GCM. [...]",
Toast.LENGTH_LONG).show();
This message is causing the exceptions...
The solution is:
call the function in the UI thread so that the Toast messages work and
enter code heremove the AsyncTask to only cover the actual network code.
Sorry for not giving all the details. I did not think that the Toast message was the root cause.
I learned that you cannot have Toasts in AsyncTasks. The always have to run on the UI thread.
I've seen few questions nearly identical to mine, but I couldn't find a complete answer that satisfies all my doubts.. so here I am.. Suppose that you have an activity with an inner class that extends the AsyncTask class like this:
public class MyActivity extends Activity {
private class DownloadImageTask extends AsyncTask<String, Void, Bitmap> {
protected Bitmap doInBackground(String... urls) {
return DownloadImage(urls[0]);
}
protected void onPostExecute(Bitmap result) {
ImageView img = (ImageView) findViewById(R.id.img);
img.setImageBitmap(result);
}
}
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
new DownloadImageTask().execute("http://mysite.com/image.png")
}
}
Suppose that the activity is paused or destroyed (maybe the two cases are different) while the DownloadImageTask is still running in background.. then, the DownloadImageTask's methods that run on the activity UI thread can be triggered and the DownloadImageTask may try to access Activity's methods (it is an inner class, so it can access the methods and instance variables of the outer class) with a paused or destroyed Activity, like the call to findViewByID in the example below.. what happens then? Does it silently fail? Does it produce any exception? Will the user be notified that something has gone wrong?
If we should take care that the launching thread (the Activity in this case) is still alive when running-on-UI methods are invoked, how can we accomplish that from within the AsyncTask?
I'm sorry if you find this as a duplicate question, but maybe this question is a bit more articulated and someone can answer with greater detail
Consider this Task (where R.id.test refers to a valid view in my activity's layout):
public class LongTaskTest extends AsyncTask<Void, Void, Void>{
private WeakReference<Activity> mActivity;
public LongTaskTest(Activity a){
mActivity = new WeakReference<Activity>(a);
}
#Override protected Void doInBackground(Void... params) {
LogUtil.d("LongTaskTest.doInBackground()");
SystemClock.sleep(5*60*1000);
LogUtil.d("mActivity.get()==null " + (mActivity.get()==null));
LogUtil.d("mActivity.get().findViewById(R.id.frame)==null " + (mActivity.get().findViewById(R.id.test)==null));
return null;
}
}
If I run this task from an Activity's onCreate like so:
public class Main extends Activity {
#Override
public void onCreate(Bundle state) {
super.onCreate(state);
setContentView(R.layout.testlayout);
new LongTaskTest(this).execute();
finish();
}
}
No matter how long I sleep the background thread, my log always shows:
LongTaskTest.doInBackground()
mActivity.get()==null false
mActivity.get().findViewById(R.id.frame)==null false
Which is to say that the activity and its views appear to stay alive (even if I manually issue GCs via DDMS). If I had more time I'd look at a memory dump, but otherwise I don't really know why this is the case ... but in answer to your questions it appears that:
Does it silently fail? No
Does it produce any exception? No
Will the user be notified that something has gone wrong? No
The doInBackground() will keep on running even if your Activity gets destroyed(i,e your main thread gets destroyed) because the doInBackground() method runs on the worker's/background thread. There will be a 'problem' in running the onPostExecute() method as it runs on the main/UI thread and you may experience running into unrelated data but there will be no exception shown to the user. Thus, it is always better to cancel your AsyncTask when your activity gets destroyed as there is no reason to run AsyncTask when the Activity is no longer present. Use android Service if you continuously want to download something from the network even when your Component/Activity gets destroyed. Thanks.
So I'm an iOS developer learning android, and I'm having a difficult time understanding some things. Right now I have a datamanager class. In that class it has an AsyncTask to update the data. OnPreExecute I pop an activity to show it is updating. I understand I could use extras to pass initial information to the UpdateActivity. My problem is I'm not sure how to send new information in OnProgressUpdate. Here is my code widdled down:
private class myTask extends AsyncTask<Integer,String,Void>{
#Override
protected void onCancelled() {
super.onCancelled();
isUpdating = false;
}
#Override
protected Void doInBackground(Integer... params) {
//My BG Code
}
#Override
protected void onPostExecute(Void result) {
// TODO Remove updating view
super.onPostExecute(result);
}
#Override
protected void onPreExecute() {
super.onPreExecute();
Intent myIntent = new Intent(mContext,UpdateActivity.class);
mContext.startActivity(myIntent);
}
}
AsyncTask is designed to work best when nested in an Activity class.
What makes AsyncTask 'special' is that it isn't just a worker thread - instead it combines a worker thread which processes the code in doInBackground(...) with methods which run on the Activity's UI thread - onProgressUpdate(...) and onPostExecute(...) being the most commonly used.
By periodically calling updateProgress(...) from doInBackground(...), the onProgressUpdate(...) method is called allowing it to manipulate the Activity's UI elements (progress bar, text to show name of file being downloaded, etc etc).
In short, rather than firing your 'update' Activity from an AsyncTask, your update Activity itself should have a nested AsyncTask which it uses to process the update and publish progress to the UI.
You have two options:
1) Pass an instance of activity to your AsyncTask constructor in order to invoke some method on it:
new MyTask(this).execute();
So, you can do:
public MyTask (Activity activity) {
this.activity = activity;
}
public void onPostExecute(...) {
activity.someMethod();
}
2) Pass a Handler instance and send message from onPostExecute() to the activity.