Could anyone explain what does exactly happens (lifecycle of Asynctask) if for example I have and Activity with a Fragment and from this Fragment I execute an Asynctask where on the onPreExecute I start displaying a ProgressDialog and at some point I close the app while the Asynctask is still running?
As far as I've checked the Fragment doesn't call onDetach nor onDestroy and the Asynctask doesn't reach the onPostExecute method or onCancelled
If i am not wrong you are familiar with lifecycle of an AsyncTask. If not, refer
https://developer.android.com/reference/android/os/AsyncTask.html
To answer why onPostExecute method is not called when we exit the app while the progress bar is still running, I would say it is because, AT holds a reference to the Activity/Context which would be destroyed by the time progress bar decides it's job is done(bg task/thread).
Very useful blog on how to handle ATs wrt fragments and activities by Alex Lockwood.
http://www.androiddesignpatterns.com/2013/08/fragment-transaction-commit-state-loss.html
Have you set setRetainInstance(true) in your fragment, whenever you start asynctask inside a fragment with setRetainInstance as true the task will continue to run in background without interrupt which is not in the case of an activity
Please ensure that AsyncTask.doInBackground() has been completed. Or, what is more possible, your main thread is stuck somewhere as AsyncTask.onPostExecute() must be executed in main thread.
In the scenario you are speaking about, the Fragment methods "onPause()" and "onStop()" will be called (besides of the ones of the Activity which contains the given Fragment).
As those methods are being called, you should react according to what you want to do in the AsyncTask.
If that's not the case, refer to the link given by #stack_ved.
Anyway, if you want to do any kind of load inside a Fragment, I strongly recommend you to use "Loaders" or "AsyncTaskLoader".
https://developer.android.com/reference/android/content/AsyncTaskLoader.html
Related
I have a pretty odd problem here. In a fragment, I do a process and when the process finishes I show an advert that callsback to the fragment when user clicks/dismisses the ad. The problem is that in some devices when the ad calls back to the handler (that is in the running fragment) the activity containing the fragment has been destroyed, but I need to do some more work through a runnable. So, in this case the runnable throws a NullPointerException int is run method when executed.
I could just check if the activity is still alive and run just the runnable when it is, but in the cases it is not alive I still need to continue to do the part of the job that needs to be done after the ad.
How do you handle this kind of situations? I have been thinking about the problem during some hours without finding a solution to this.
Thanks in advance.
You can use AsyncTask in this case .
AsyncTask processes are not automatically killed by the OS. AsyncTask processes run in the background and is responsible for finishing it's own job in any case. You can cancel your AsycnTask by calling cancel(true) method. This will cause subsequent calls to isCancelled() to return true. After invoking this method, onCancelled(Object) method is called instead of onPostExecute() after doInBackground() returns.
Hope it helps..
mmm the way this is asked I am not sure what you are asking, perhaps some text connectors might work, I am not sure if this is a quite basic question about state changes or a very complex one.
from what I understood:
wouldn't this be the same problem as when you flip screen? make a Bundle of the data that is restored through activity changes. This way if your activity has been Destroyed you restore it
fragments have a feature that you can use to keep instance alive across a configuration change: retainInstance
setRetainInstance(true) // false by default
Parcelable like Serializable, is an API for saving an object out to a stream of bytes. Objects may elect to implement the Parcelable interface if they are what we will call "stashable" here. Objects are stashed in Java by putting them in a Bundle, or by marking them Serializable so they can be serialized, or by implementing the Parcelable interface. Whichever way you do it, the same idea applies: you should not be using any of these tools unless your object is stashable
---or---
turn that "advert" of yours into an Alert, which wont mess with the Activity.
---or---
run the response on a different thread?
I have thinking some time about this. I have an FragmentActivity in wich I have a FrameLayout and some Fragments change there. Each fragment has different layout and launches different asynctask. My question is :
Where is the best place, I mean best fragment state, to call asynctask ? I mean like I have some textviews in fragment layout and I want them to display text values based on asynctask result. Should I call the asynctask in onCreateView or somewhere else ? Making the call in onCreateView would invoke the asynctask more times as the orientation would change, as I am aware of. So what is the best practice for fragments with asynctask ?
Better to use AsyncTaskLoader instead AsyncTask with fragments
When you create the Asynctask in onCreate it gets called only when the fragment is created. When you call it in onResume it gets called even after the user returns gets a phone message. So it depends on how up to date you want the data.
You could even call it in onViewCreated but it really is up to you. You can also call it in the application object so the asynctask is executed only when the user starts the app.
AsynchTask got onPostExecute() method tied to UI thread. Assume that we close an activity by pressing back button while AsynchTask doInBackground() method is still in progress.
I want to know will onPostExecute executes by considering that activity is not displaying on screen anymore?
In case answer is yest, will it cause exceptions or not? (because of accessing UI objects which are not longer displayed on screen).
1-I want to know will onPostExecute executes by considering that
activity is not displaying on screen anymore?
yes!
2-In case answer is yest, will it cause exceptions or not? (because of
accessing UI objects which are not longer displayed on screen).
Yes! it may cause Exception because your Instance of your Activity and Views which you use in your AsyncTask are not exist anymore
This Link will help you more : AsyncTask won't stop even when the activity has destroyed
My Problem: Is it possible to prevent an activity to call OnResume() when it is being created? As I saw after the OnCreate() and onStart() method runs, the next one is the onResume(), although I only want to have it when I resume the activity from the paused state.
Why do I need this: I launch my activity (FragmentActivity, so lets say OnPostResume() ) starting with a thread which takes about 2-3s to be ready getting data from an external database. After the thread is done, I call a method which needs these data and I want to call it everytime that activity gets visible. The thread runs only when the FragmentActivity is created (onCreate()), and I cannot put the method into the onResume() because onResume() would be running way before the thread would finish its task. So it would receive not-ready data.
Anyone has a better idea?
Not sure of the exact application of this but I'll make a suggestion.
If you use an AsyncTask, you can send it off to get the data you need and in the onPostExcecute() method you can call your method that requires the data or update the view as needed. (It runs on the UI thread)
If you happen to already have the data you need in certain scenarios you could also bypass the AsyncTask and directly update the view.
This AsyncTask can be triggered in the onResume() method.
If I'm missing something, please let me know and I can adjust my suggestion.
I didn't understand the purpose of this, but here's a possible solution:
If you only wish to get the even of onResume on states that didn't have the onCreate before, just use a flag.
In the onCreate, set it to true, in the onResume check the flag (and also set it to false). if it was true, it means the onCreate was called before.
I personally would prefer to check if the result available, rather than always executing the getter-code in onResume. If the user somehow resumes your activity before the background thread is finished, you'd have a call on onResume, but don't want to display a result.
Maybe it would be a good idea to calculate/fetch the values in the thread, and let the thread return immediately (and cause the values to get filled in) if the values are already cached somewhere. That way you'd only have one entry point (the thread) for updating your UI instead of two (the thread and the onResume method).
I have several Activities and each of them has its own AsyncTask which sends requests to a server and catches its responses. These days if AsyncTask is in execution I have a ProgressDialog which blocks User from navigation to another Activities. I want to get rid of the ProgressDialog and substitute it with ProgressBar view so user can switch between Activities. My concern is about the following: what if AsyncTaskFirst started in ActivityFirst and user navigates to ActivitySecond where AsyncTaskSecond is starting also, couldn't it happen the response from the first request will take ground in ActivitySecond so I'll miss it in ActivityFirst? If it is impossible, that's fine. If it is - how to handle such a case? Thank you very much in advance.
If the AsyncTask begun execution in the first Activity then it's execution of the postExecute method should be expected to affect the first Activity and not the second unless you've explicitly set it up otherwise.
I assume your AsyncTask has some kind of reference to the Activity, so it can update the progress bar.
If this is so, then all you have to do is add a method in the AsyncTask:
public void setHandler(MyTaskHandler handler) {
this.handler = handler;
}
When you start a new activity, call this method and pass on the new activity.
Then when the AsyncTask calls the Activity's update progress method, it will use the current Activity regardless of where the task was started from.
BTW: It might be better to use fragments and not activities, if it's the same component only different parts of the display. Then you do not have this problem at all, because the activity remains the same. See these guides about fragments:
http://developer.android.com/training/basics/fragments/index.html
http://developer.android.com/guide/components/fragments.html