Android, understanding AsyncTask - android

Are specific AsyncTask's for specific activities? Or could I have say a RESTful APIManager which called one of four AsyncTask Classes, APIGET APIPOST APIPUT APIDELETE and be able to handle the network code that way? My idea is to be able to call something like this throughout my UI code.
<edit> Class UserPrefs;
APIManager.createUser(JSONObject info);
APIManager.createUser {
// handle info
APIPost newPost = new APIPost(info);
}
APIPost extends AsyncTask {
doInBackground {
//network code
<edit> UserPrefs.save(result);
}
}
Would this model be possible? Or am I misusing AsyncTask?

AsyncTasks are a natural fit for a RESTful service, but they are not tied to the lifecycle of Activities. You may create and start an Async task, but by the time the task finishes its background work and calls onPostExecute, the originating activity no longer exists in memory. Because of this, you should have a better plan for how to store local data than to keep it in an Activity member, where it can and will disappear frequently. To avoid thrashing, you should save the data somewhere. Candidates for saving local data are SharedPreferences, the file system, a database or the Application singleton object depending on the nature of the data and your app.

You could use ExecutorService, AsyncTasks are using it internally. Very easy to use.

Related

Keep app integrity when using asynchronous calls in android

I am trying to keep my app clean by using good design principles. I want to keep the view, the logic and the database layers separate.
On the app I am working on now, I have a main activity, a singleton, a logic class and a I use room for the database access. I would like the activity to tell the logic to fetch data from the database and then load it in the singleton. Once it is done I need the main activity to show the data loaded in the singleton.
Room use LiveData. How can I use LiveData and then somehow return a result to the logic layer then load it into the singleton and let the main activity now that it is ready?
More generally, how can I tell a caller, from the callee, that the data is ready when it is asynchronous? For example if the main activity calls a logic class in another thread to load data, how can the logic class then let the main activity know it is done?
You can use a Handler to update the main activity on the UI thread:
LogicClass.functionThatAccessesRoom() {
//get data from Room
//...
Handler handler = new Handler(Looper.getMainLooper()) {
#Override
public void handleMessage(#NonNull Message msg) {
//update the UI/views here
}
};
handler.obtainMessage().sendToTarget();
}

What is the best way for fetching data and for passing to another Activity?

Most the app so far I had created, I fetch the data from Network and store it in a singleton class to share data between Activities, when I'm done with those data, I usually clear those setting it to NULL, its work perfectly well
My Question is which approach is better ??
Use parcelable
Writing in database and Query for it
Singleton classes
When exactly we need to use Loaders ?? Why we can't share the data through Loaders ??
If question is repeated ... Please ignore ??
Answer to first part
Parcelable:
The best way to pass data between Activitys or Fragments is by using Parcelable objects. It is said to be more optimised than Serializable. There are couple of libraries/plugins which can help you create Parcelable objects. Lately I was referred to Parceler, created by John Carl. However, I personally use Android Parcelable code generator by Michal Charmas, plugin for IntelliJ IDEA and Android Studio.
DataBase or SharedPreferences:
Using DataBase or SharedPreferences to pass data between Activitys or Fragments sounds weird, and since they are not designed to be used this way, it will only create a mess.
Singletons:
Read this very informative post Singletons are Pathological Liars.
Conclusion:
I recommend Parcelable or if you want to be real lazy then go for Serializable (it's not terrible but it's not great either, according to most).
Don't mess up your code by using singletons, DataBases, static fields, etc. They will come back and haunt you.
Answer to second part:
When exactly we need to use Loaders
Loaders, which will be AsyncTaskLoader when you use, are basically used for situations where we want to retrieve data from the server (via web API), or doing something in background. It is similar to using Thread or AsyncTask but is very powerful as it isn't destroyed on screen rotation, unlike those two.
You should read How to Use Loaders in Android and Alex Lockwood's posts on Loaders (this is a series of 4 posts. Very detailed and great).
It all depends on the way you want to use the data.If you want to use the data in future, as in after the application is killed and re launched you should save it in a database.
I would prefer parcelable over a singleton as I don't have to bother about clear the data.
According to the Documentation we generally use loaders to load data asynchronously and to monitor a the data source for change. To my understanding you aren't doing either of them, hence loaders are not required in this case.
1.Database: If you are going to use the network data in future or you are going to do some query operation to perform filtration according to requirement,it is preferable to go with db.
2.Singleton Class: Most of the developer use this because it is more efficient,the values can be changed and retrieve easily with the help of getters and setters.
Here is a very cool way of passing data to another activity I read this somewhere else on Stackoverflow and always use it now. It may not fit your use-case but it sounds like it will.
For example, say you want to pass a parcelable "DataModel" from ActivityA to ActivityB.
Inside ActivityB create a public static method called 'start' like this.
private static final String DATAMODEL_KEY = "datamodel_key";
public static void start(Context context, DataModel dataModel) {
Intent intent = new Intent(context, ActivityB.class);
intent.putExtra(DATAMODEL_KEY, dataModel);
context.startActivity(intent);
}
To start ActivityB simply call the 'start' method above like this
ActivityB.start(this, datamodel);
Use 'this' if called from an activity, or 'getActivity()' from with a fragment.
This will contain the code for starting ActivityB inside ActivityB, like the private static final DATAMODEL_KEY field and such. To answer your question though, go with option 1 and use parcelables and try out the code I posted above to help with starting the Activity with the data.

Update Fragment after Async Task completes

I have a viewpager fragment setup, and I have an AsyncTask run at the start of the activity to load some data from a JSON get (the data it pulls only needs to be done once, and all fragments will use it). The problem I'm having is I want to take this data from the AsyncTask, and have it be the data that all of the textviews pull from in the fragments.
What would be the best way to load data from an AsyncTask and then have the fragments reference that data. You cant just have the views reference the data from the get-go as it Nullpointers, and I'd really like to avoid having to reference every single textview in the OnPostExecute of the AsyncTask if I had it in the Parent Activity.
Just decouple the storage of the data from the view(s). In that way it will be easyer to handle the download of the data and to show it in the various fragments once the get is completed.
The basic idea is: launch the download in a background thread decoupled from the activity (service or intent service), then update the data a storage (sqllite if it is complex, shared preferences or even a singleton object, even though I don't like the latter approach).
Once the get is performed, inform the fragments that the data is available. Still, you have a lot of options here. If you decided to host the thread / asynctask inside a service, you can bind a callback to it and then notify all the fragments interested, you can use a (local) broadcast message that you can intercept using local broadcast receivers, or you can even use a message bus such as otto.
Finally, I really recommend to use an intent service to perform the async job. It's the easiest way to do any one shot operations without having to deal with service creation and/or with activity configuration changes.
Not sure if this is the "best" way, but what comes to my mind first is the famous Observer pattern.
Create an interface called Observer with a single method called
notify()
Implement this interface in all Fragments that want to be notified when the data is ready
Hold a List of Observer objects inside your AsyncTask
In onPostExecute(), traverse this List and call notify() on every Observer, passing the appropriate data
React on the notification inside your Fragments given the data
This a very rough description of this solution, but I hope you get the idea.

Save multiple instances states of the same Activity in Android

I am developing an Android app and I would like to avoid reloading similar data when it comes from the same Activity using the same extra.
Specifically, when I launch my Activity 'A' with extra, I use this extra to load remote data from server.
From this Activity, I can relaunch 'A' with different extra and so on.
Example :
A:id1 --> A:id2 --> A:id3
But, it can also be an extra that I already loaded :
A:id1 --> A:id2 --> A:id3 --> A:id1
In this case, I wouldn't request the server again or lose the activities stack.
As I understand, "onSaveInstanceState" allows to save one instance of one Activity, but in my case, it's multiple instances of same Activity (with differents extras).
So, is it the solution to manage a list of saved instance states (bundle) for the same Activity ? Or something else ?
Thanks in advance
The onSaveInstanceState method isn't used in the way you describe. Check this out, it's the documentation for the Activity Class, specifically the Activity Lifecycle section. onSaveInstanceState is a method that gets called when the OS has to kill an Activity for some reason. It allows you to populate a Bundle which will help recreate that specific instance of the Activity where the user left off. Usually this happens because the user switched to a different app and the OS is killing the Activity to reclaim memory, but also happens on screen rotation, so it's a nuance of the platform that is important to at least be aware of.
As for your question, what I would do is use a database to store the information that is retrieved from the server. When you start an Activity, you can first check to see if the data that needs to populate that Activity exists in the database. If it does, load and display it from there, else make the server call.
This is nice, because the data will be persistent over multiple uses of the App. Going further, if the data from the server has the potential to be stale, you can easily extend this to display the data from the database initially, and fire off an asynchronous request for the data that will update both the UI and database when it returns. Your user will almost never be in a state where they're waiting for things to load, which is always a good thing!
Here's a good tutorial on the basics of implementing an sqlite database. This will also give you the added benefit of keeping the data stored over separate runs of your application.
As an alternative, if you don't really need the persistence or other features of the database and don't think that the overhead is worth it, you could create a Singleton class which keeps track of the data as its returned, perhaps implementing it using the Application class. It's important to note (and bringing us full circle) that any in-memory method of storing this data should be managed with onSaveInstanceState to ensure you don't lose any data if the Activity is killed at an unexpected time.
+1 for MattDavis' answer, but I'd also suggest you use what's known as the "singleton pattern".
Essentially, this is a way to cache things in memory. You create a class whose purpose is to hold all the database data you don't want to keep reloading. There's a single global instance of this object, which is initially null. You call a static method that returns that instance. If the static method finds that the instance is null, it creates the instance, populates it from the database, caches it, and returns it to the caller. From that point on, all requests for the instance just return the cached copy. If your app gets killed by the system for lack of resources, and started again later, it transparently re-creates the instance as needed.
This is a very common implementation, and works in a multi-threaded environment:
public class Singleton {
private static volatile Singleton instance = null;
private Singleton() {
// This is the place where you initialize the instance
// from the database.
}
public static Singleton getInstance() {
if (instance == null) {
synchronized(Singleton.class) {
if (instance == null) {
instance = new Singleton();
}
}
}
return instance;
}
}
I use this pattern in a lot of places; it's very handy.
To really do it right, you should also implement onLowMemory() or onTrimMemory() in your activities to release the singleton instance when resources are tight.

How do I get return value from AsyncTask to Main Activity?

I have a class (like a helper class) -not an activity- which manages soap requests. I use this class to send soap requests that comes from activities by method doInBAckground and catch all return values from webservice by onpostexecute. Everything is ok but my problem starts at this point because I could not pass return value asynctask class to main class.
You can have some utility class available as singleton (ok, singleton is dangerous pattern
but it use is justified in android until we get sane and usabel dependency injection ) and pass result there.
Advandatges:
- no messing with intents / serialisability
- pass data or call some methid or do whatever you like
- all your activities share the same instance of singleton service.
Disadvantages:
- singleton pattern is considered dangerous
You may even go further and make your service singleton - you will start methods of it as async tasks, and then your activity may query results over dedicated methods.
Or you may go a step further - register your activity as listener in async service, and call method in this activity when ready (note: as this will be not a UI thread, you will be unable to do something with UI unless you use runOnUiThread()
Have you tried implementing the AsyncTask as an inner class of your Activity?

Categories

Resources