Using AsyncTask to preload data for a new Activity - android

I have my MainActivity which gives the user a selection of pages to open, all of which involve downloading some data from the internet and displaying it. To save the user waiting when they choose their page I've made an AsyncTask as a subclass of MainActivity which produces an object DATAwhen the download is complete.
How would I pass DATA on to the SecondActivity in the following circumstances:
The user chooses the SecondActivity before the AsyncTask download has completed.
The download completes before the user chooses the SecondActivity.
the AsyncTask doesn't have to be a sub-class of MainActivity its just been tidy to do it that way so far,
thanks for the help!

Here's one way to do this:
Create a reference to your data in your Application. The Android Application is a good place to store global data. Next, populate the data via your AsyncTask (Watch out for the pitfalls of using an AsyncTask). You can now access your data via a call similar to this: ((MyApplication)getApplication).mydata
As you mentioned, two scenarios can come up. Either the data has been populated, or not. To handle this, use an observer that observes changes to the data. Have SecondActivity register as an observer when the data is null. When the data is available your SecondActivity's update method will get called and you can do whatever you please with it. Finally, make sure to unregister from being an observer.
Hope this helps.

Passing information directly between activities works only if it is Parcellable (via Intent). Almost anything could be made Parcellable but it is not always a good idea especially when the amount of data is large.
The next problem is that your AsyncTask most likely keeps the Context of your first activity alive when it is running longer than the activity lasts. Activity instances are quite often recreated when you rotate the device and naive implementations tend to start another asynctask in the new instance and end up with multiple tasks that download the same data. You would need to pass the reference of a running task between instances of the same Activity.
The simplest solution is probably to create a singleton (or a Service) accessible from both activities that hosts the AsyncTask & loads the data. If it requires a Context use getApplicationContext() since that's safe to use outside the lifetime of Activites.
Activities could register themselves as listeners for "data loaded" events while they are active.

I've recently struggled with AsyncTask and had difficulty having the UI behave while the task was running in the background. While there are comments around that services aren't really appropriate for the sort of thing you're describing, I've found them much easier to work with. You might check intentService as a middle ground. Good tut's can be found here and, specifically concerning intentService, here.

Related

Always use services in android?

I've read by many people to not use AsyncTask for web requests, but rather use IntentService, since AsyncTask is bound the lifecycle of its activity. is that always the case? cause I'm making a social media app, And I wonder if each action the user makes should launch a service (for example, press like, add comment, etc)?
Do not use AsyncTask, as you may have read, it is problematic on Activity recreate. However, you may use AsyncTaskLoader with LoaderManager, which is designed to fix the problem.
And there is one point you are wrong with IntentService, you do not launch a service everytime using IntentService. You are submitting requests to the same service only (unless it is being killed), and the IntentService pull requests from the stack.
I tend to use a mixture of both. I use an IntentService when requesting/posting data from a server, then deserialising it and storing it locally. All this could take several seconds depending on the amount of data returned and the server's response time.
I would use an AsyncTask within an activity if I know that the request is going to be very quick. I use it for more fire and forget small tasks.
The important thing to bear in mind is that your AsyncTask is tied to your activity. And if your activity gets destroyed (due to an orientation change etc.) then you could easily have an NPE in the onPostExecute().
If the task you wish to perform is specific to a Context and is considered garbage once you leave the Context, such as if you consider the user session to be invalid once they leave, then an AsyncTask is a good choice.
However, if the task is specific to a context and may take a long time to perform and you want the user to be able to leave and come back later to see the result, a service may be well suited even though the task is specific to a Context.
If the task you wish to perform is applicable outside the scope of a Context, then a service may be better suitable.
If you just always use a service, you'll probably be over complicating your code.

Recommended design approach for web service downloading/importing within app

My app needs to initially download data from two different web services (JSON) and import them into it's local database (Realm). I have two activities that need to display data from these web services. The first one (HomeActivity) is the initial activity that the app loads. The second one (LineupActivity) is created when navigating to it from the HomeActivity.
Currently, I've created an Application class (extending Application) in order to handle the web service downloading and importing. In it's onCreate(), it calls two methods, which are AsyncTasks that download and import each web service.
The reason I've added this download/import process into the Application class is for 2 reasons:
I want all the app data to be downloaded as soon as possible, so
when navigating to the second activity it doesn't need to initiate
another download.
Both these activities have swipe to refresh. They call each respective method in the Application class to re-download/import the
web service data.
Have I approached this incorrectly? Should I move the web service download/import logic out of the Application class? Also, does the onCreate() of the Application class get called more than once? Meaning, I know that it only gets called only once in the application's lifecycle, but does the Android OS eventually kill an app and have it call the onCreate() in the Application class when starting it again? I want the app to download fresh data upon startup, but not every time the user brings the app into focus.
Have I approached this incorrectly?
"Incorrectly" is a very relative term in this context.
Metaphorically, its like the context is never null but that doesn't determine boolean incorrect is true or false.
Should I move the web service download/import logic out of the Application class?
I would say Yes, as the download logic would not be related to the O.S. and the app being alive in its memory. Your requirement does not seem complex. Service would be necessary if the downloads are huge chunks of data, and if its not necessary, don't do it.
Also, does the onCreate() of the Application class get called more than once? Meaning, I know that it only gets called only once in the application's lifecycle...Application class when starting it again?
No, it won't be called more than once without app being killed and restarted. And what your are saying is correct, but for your requirement, there are probably more efficient and lighter ways to do it rather than combining it with an Application class.
For the rest of the logic, you could implement Asynctasks as a separate class and implement interfaces which are the callbacks of the result of your task. This would help in Swipe-to-refresh functionality.
In terms of documentation reference, Application class
There is normally no need to subclass Application. In most situation,
static singletons can provide the same functionality in a more modular
way.
Your case seems exactly that.
One thing you need to decide is When, how often do you need to refresh/download the data. For only start-up of the app or once daily, you can store date/day in SharedPreferences and check the value in onResume() of your Activity.
You can also implement inheritance with a Base Activity with the necessary download check logic in it and extend your classes. A Splash Screen would always help to initiate the downloads.
I suppose you could approach this anyway you want, though I like to implement one of the three options mentioned here: https://dl.google.com/googleio/2010/android-developing-RESTful-android-apps.pdf.
The presentation itself can be found here: https://www.youtube.com/watch?v=xHXn3Kg2IQE.
This does however not mention how you should sync on startup. But you could just set a SharedPreference in the application class and then use one of the patterns to sync in the background.
I'd recommend you instead of using Application to download your stuff to use a Service. If by any reason your app gets killed by the OS your dl's will never complete. Using a Service it will.
Also, you can use a Broadcast to your activity to signalize that the service has completed downloading and taking the necessary following steps.
first: I think it's bad to place the download at appliaction onCreate
as stated in documentation
Called when the application is starting, before any activity, service,
or receiver objects (excluding content providers) have been created.
Implementations should be as quick as possible (for example using lazy
initialization of state) since the time spent in this function
directly impacts the performance of starting the first activity,
service, or receiver in a process. If you override this method, be
sure to call super.onCreate().
pay attention to this part
Implementations should be as quick as possible (for example using lazy initialization of state) since the time spent in this function directly impacts the performance of starting the first activity
so any delay in download or import may cause the first activity to be delayed.
and the behavior is not clear, a black screen maybe?
Second suggestions for download/import:
1- use an AsyncTask in the first activity, where you display a small progress bar indicating the download/import process or even block the whole UI until completed (based on your business)
2- add a splash screen while downloading the data
regarding fresh data, you can store a timestamp, last_updated
and before starting the download/import process, check that value, if less than your accepted value (say 1 hour) don't start the download/import.
finally, regarding onCreate() call, i think it's not called everytime, only when app is re-created, like 1st run after reboot, or after being killed or forced close.

multiple asyntask

This is somewhat design specific question but I am looking for right advice.
In my app I have 6 pages A,B,C... each of which will download data from server and display it. In this case among below mentioned approaches which one will be good.
1.For each A,B,C write inner asynctask class
2.write separate asyntasks like asyntaskA,asyntskB etc for each of these activities
3. write a single asynctask and route request of each activity through a requestcontroller class which creates instance of asyctask by passing context,url parameters
If the second approach is taken, is it possible to run one Activity and another Activity in onpause state while its asynctask still running?
In each page, if you are doing the same kind of operation (As in this case, downloading data and displaying it), you need not write separate AsyncTask classes. Just create as much instances as you need and call the execute() method. AsyncTask class will handle this in thread safe way.
Second part of your question is bit unclear, but if you meant switching between activities, it is possible with multiple instances of a single AsyncTask. You'll need to save and restore the activity states.
If the operation you performing is time consuming, say more than few seconds, it's not safe using an AsyncTask. The better option will be a Service.
There's no problem with multiple AsyncTasks. In one of my apps I have a grid-view with images and there's an AsyncTask for every image loading and generating a thumbnail image. They all run in parallel quite nicely.

Android - Running heavy computations in background and returning the result to an Activity

I have implemented some computationaly heavy functions into my application. Depending on the type of input it can take up to several minutes for a thread to return. During this time, I want the user to be able to work with other activities to perform different tasks (i.e. prepare data for the next run). Then, after the Service has finished it's computations, the user should be notified with a Toast that the result is ready and that he should check back to the Activity he started the Service in. Unfortunately I'm stuck at this point.
Is it possible to somehow communicate with an Activity which is destroyed at the moment? Like modifying the saved state, so that when it get's recreated the result will be displayed. The only way of communication I did find was via broadcasting from the Service, but this requires the Activity to listen, which is not possible as it doesn't exist at the moment the Service finishes.
The only solution that occured to me was writing a file when the Service is finished and then trying to read it in the Activity, but I would prefer not to work with the file system if that's possible.
Am I missing something here or thinking in the wrong direction?
use Asynctask
http://developer.android.com/reference/android/os/AsyncTask.html
You could just write to a SharedPreference from the Service.
The Activity can check the preference whenever it is started and you can have some marker to indicate that the result was from your computation.
You could also write to the same SharedPreference from the Activity to nullify it so that it can be used for the next result.
I would use an AsyncTask, and return the value from your computation to some stateful location (use an Application class, or SharedPreferences even).
Have the AsyncTask launch your Activity on completion, and get the value you statefully stored to display.
Basically, combine the 1st 2 answers and you should be set.

Android invoke asynctask from whole application

I need a little information/help/suggestions how can I build my application so I can use one AsyncTask from all activities which will download some data over internet. The problem is that once I run the asynctask from one activity, I want to download whole information again but to update only the information which I'm showing in that activity (like listviews, showing the images and etc.). And I'm not really sure how can I code this.
If anyone can offer me some help/suggestions even example it would be great!
Thanks a lot!
The most common way we use AsyncTask is defined it as a inner class of a Activity. By doing this, we bind the AsyncTask's life cycle to its master - Activity, As we know, the Activity's life cycle is quite transient and usually get created/destroyed many times during application running time. So...
how can I build my application so I can use one AsyncTask from all activities which will download some data over internet
In my opinion, the most reasonable solution here is Service, obviously service has a more solid life cycle than Activity/AsyncTask. You can implement a service that download data in thread, make it keep running during application running time, and update your current foreground activity's UI stuff from service. check out more details in this SO question.
Hope that help.

Categories

Resources