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.
Related
I have 3 Fragments inside a ViewPager. I call an API in onCreate() of the first Fragment which returns JSON data (second and third Fragments are empty).
The problem is that onCreateView() is always executed before getting data from API, so I need to swipe two times to right which will call onPause() method of the first Fragment, and then I need to come back to the first Fragment which will call onCreateView() of first Fragment and this time because data has been loaded from the Internet, it will show data.
How can I overcome this problem and force the first Fragment to show data on the first onCreateView() call?
You need to make the API calls in AsyncTasks, in background, and in onPostExecute(Result) method do your UI updates.
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
I have a FragmentActivity with 7 tabs, and all of them refers to the same fragment, the only difference is a parameter, that makes them to load throught an ASyncTask the data to show from a PHP that returns a JSON. My problem is that when I swipe from one tab to another, if the task from the first tab is still loading, it loads in the new tab, or crash, or doesnt do anything. However, the activity load two tabs, so the task is launched twice and is the same problem. Any idea?
While AsyncTasks are wonderful to have, they are intended to be procedures that are independent of any UI (e.g. saving information). For the longest time I was in the same boat and used AsyncTasks for work that would end up changing the UI (since hey, they have an onPost method).
What you should be using for any work that will affect the UI is called a Loader which will pay attention to the UI state of the Fragment. In your case the AsyncTask is probably attempting to access a UI element that no longer exists (View Pagers only keep the previous, current, and next views in memory). The Loader will pay attention to this and not attempt to change the UI.
There are plenty of examples out on the web, but in short you will need to create (extend) a Loader for each of your AsyncTasks (I recommend AsyncTaskLoader, if you do pay attention to forceLoad) and add the callbacks (LoaderManager.LoaderCallbacks) to your Fragment. Then when you are ready to load call getLoaderManager().restartLoader(LOADER_ID, bundle_args, loader_callback);
Keep a reference of your AsyncTask. I assume you have a callback which let's you know when the tabs have changed. When you get notified that tabs have changed you can check if your AsyncTask is null or not finished yet, if it isn't you call it's cancel() method.
if(asyncTask!=null && asyncTask.getStatus()!=AsyncTask.Status.FINISHED) {
asyncTask.cancel(false);
asyncTask = null;
}
First and foremost:
*I have Fragment classes which serve as a class for each page in the viewPager.
*Each fragment class has its own AsyncTask.
My problem here is that the AsyncTask's of each fragment class are called at once when the class that has the ViewPager is called. I know because in each of the AsyncTask's onPreExecute() i put a ProgressDialog. I am expecting that every time I swipe and go to another page, that should be time when the AsyncTask of each of the fragment class will load, not on the first page all at once.
I tried putting the AsyncTask.execute() on the onActivityCreated(Bundle) but still nothing changes.
Also, every time I swipe pages, the ProgressDialog inside the AsyncTask's onPreExecute() shows up. I placed a Log in every onPreExecute() but surprisingly it prints one time only ever since theviewPager` is called.
If you want each AsyncTask started only when your Fragment is visible, you must execute it from either the Fragment's onStart() or onResume() method. The reason they're all being called at the same time is because a Fragment's onActivityCreated() is called when the parent Activity is created, not when the Fragment is visible. Take a look at the lifecycle of a Fragment to see when it would be most appropriate to execute your AsyncTask.
Additionally, since you are using Fragments, I would highly suggest using a Loader as opposed to an AsyncTask. They are much easier to manage alongside of a Fragment.
I have this problem. I have an activity and a fragment inside it. I am downloading some data using async task in activity's onCreate and then using it in the fragment's onCreate (something like getActivity().getData()). I am putting the fragment into a view after the data is loaded so it runs without trouble. The problem is that when I'm relaunching the activity from background and this fragment is active it loads immediately and throws an NullPointerException because the data isnt loaded yet. My idea was to check for this in the fragment's onCreate and if I get null data I'll just destroy it and call some activity's method for reloading data and then lauch the fragment again - is it even possible?
Do you have any solution for this or maybe a better approach?
If it's possible to cache the data on the phone, I would consider it.
If you have to reload the data on every (re-)start (more like: every resume) of the app, take a look at the activity lifecycle in the android documentation:
http://developer.android.com/reference/android/app/Activity.html
Your problem should be solved, if you #Overwrite onResume() of your activity and load your data there, instead of onCreate()