How to get multiple implementations of a single AsyncTask class in Android? - android

I am developing an Android application, where most of my activities are fetching content from a MySQL database separately, through an http request.
For this, I am required to add the AsyncTask class separately to each such activity.
Is there a possibility that I may use a common AsyncTask class for all such data fetching and create their objects separately in the activities and fetch data based on the parameters?

Of course, you can create separate class extending AsyncTask for making HTTP requests, which will take appropriate parameters and re-use it in many activities. You don't have to create nested private classes in each activity. You can use input parameters of AsyncTask in doInBackground(parameters) method. See documentation of AsyncTask at: http://developer.android.com/reference/android/os/AsyncTask.html
Below, you can see very simple example of using AsyncTask with some pseudo-code:
public class DownloadDataTask extends AsyncTask<String, Integer, String> {
protected String doInBackground(String address) {
// you should have method for performing HTTP request
// and return result - in this case as String
String result = performHttpRequest(address);
return result;
}
protected void onPostExecute(String result) {
// this method is executed after downloading result
// now, you can perform some action - e.g. display data in a TextView
myTextView.setText(result);
}
}
In this definition: AsyncTask<String, Integer, String> first parameter is type of input parameter (in this case address of the end-point), second parameter is type of progress value (we are not using it in this example), last parameter is type of output value (in our case, HTTP response as String).
When DownloadDataTask class is placed in a separate file, you can re-use it in many activities with the following call:
new DownloadDataTask().execute(address);
Of course, it's very basic example with some pseudo-code. I haven't initialized TextView and I haven't provided implementation of performHttpRequest() method. You should adjust it to your needs. You can also upgrade this solution and pass reference to a TextView or another widget in which your result will be displayed.
Nevertheless, consider using RxJava and RxAndroid instead of AsyncTask. It will make you app simpler and less error-prone. I do not recommend using AsyncTask, because we have many better solutions for Android right now. Regardless of this fact, you decide which solution will be used in your project.

You can achieve this in much the same way as you would with any other Class - create a separate class file that extends AsyncTask and create an object where it's required.
For more flexibility, you could declare the class abstract and use an unknown type parameter, so that you can adjust it as your requirements change.
public abstract class MyTask<T> extends AsyncTask<T, Void, Void>{
#Override
protected void onPreExecute() {
Log.i("Tag", "onPreExecute");
}
#Override
protected void onPostExecute(Void aVoid) {
Log.i("Tag", "onPostExecute");
}
}
And then, whenever you want to create an instance:
MyTask<String> mt = null; //Or URL etc.
//...
if (mt == null) {
mt = new MyTask() {
#Override
protected Void doInBackground(String... params) {
return null;
}
};
}
mt.execute(params);

Related

can use variables from doitbackground in onpostexecute

I have a inner class of asynctask in a class. I defined some variables arrays in that inner class. In doitbackground, i put some values into them.
When i go go onpostexecute, i can use them because they are all in same inner class.
So, i dont need to return something for pass? I am really confused. Is that a bad way, should i define all those inside doitbackground?
Because if i have to pass values, i need to define wrapper because i have to pass 4-5 arraylists. They are different types. But now i can use them and no need return or pass.
I am searching but there is no information about this. In all asyntask examples, they define variables outside of doitbackground.
I usually create a class with these fields in a doInBackground, and pass this class as a result.
This also allows you to pass null if an error happened.
class DataClass {
private int someIntData;
private String someStringData;
}
new AsyncTask<Void, Void, DataClass>() {
#Override
protected DataClass doInBackground(Void... params) {
DataClass data = new DataClass();
// doing some job
if (!errorHappened) {
data.someIntData = 5;
data.someStringData = "Just an example string";
return data;
}
return null;
}
#Override
protected void onPostExecute(DataClass result) {
if (result != null) {
// handle the result
} else {
// error happened
}
}
};
Technically you can do it, but think about encapsulation concept
as you know,
doitbackground happen in another thread than ui thread
onpostexecute happen in ui thread
so there is common pattern that send AsyncTask parameters in Constructor or Execute Argument, by this way, you can make your self sure that Async class can be reused maybe in another application and fully encapsulated.

Call different callback from AsyncTask onPostExecute()

I have implemented an internal AsyncTask for my class that does initial setup data query from server and stores into device cache. The setup data in split between 2 JSON files. The first JSON is read/cached and if certain conditions are on then second JSON file will be downloaded and stored into cache. I want to use same AsyncTask from both operations.
In doInBackground(), I perform JSON download operation independent of JSON type. But in onPostExecute() I want to call different callbacks depending if its 1st JSON file or second, since they require different handling. Is that possible?
EDIT: Pls note I do not want to use booleans, enum to decide which callback to call as in future I will have more files to process. From my calling class I want to set the callback and rest should happen automatically.
Below implementation should solve your problem:
private class MyCustomAsyncTask extends AsyncTask<Void, Void, Void>{
private boolean mShouldCallMethod1;
public MyCustomAsyncTask(boolean shouldCallMethod1){
mShouldCallMethod1 = shouldCallMethod1;
}
#Override
protected Void doInBackground(Void... params) {
//code goes here..
return null;
}
#Override
protected void onPostExecute(Void result) {
if(mShouldCallMethod1){
method1();
}else{
method2();
}
}
}
i.e have a customized AsyncTask as innerclass.
If you use the same interface which contains the two callbacks this is no problem. Simply declare an interface with 2 callback methods (json1, json2) and pass an instance of the interface to the AsyncTask.
In your onPostExecute() you can call the callback(s).
As android does not support setListner Methods for onPostExccute so there is two ways:
Extend AsychTask and imlement setOnPostExcuteListner
Or just call "your method" from onPostExcute simple!

Use Asynctask as a private class or with broadcast receiver?

I'm trying to make an application that uses Asynctask. Particularly, I want to make different http petitions with different JSON in different activities without the activity being frozen while the communication is done.
At first I thought to use asynctask as a private inner class in those activities, but I saw that they share a lot of code. So I thought to make a single class and play with broadcast receivers as I need to monitorize when I receive the result of the http petition, and isn't good to interfere with activity directly in the onPostExecute while in a different class.
What I want to know is, what is more efficient and better practice. Make a class that has the shared code and extends asynctask, then doing inner classes for each activity that extends that one or make a single asynctask that sends broadcast and receive them with each activity when needed.
Excuse my poor english, if needed I'll try to specify more clearly.
Thanks in advance
Background
What I want to know is, what is more efficient and better practice. Make a class that has the shared code and extends asynctask, then doing inner classes for each activity that extends that one or make a single asynctask that sends broadcast and receive them with each activity when needed.
I'm unclear as to why these are your only two options. Create a single AsyncTask, such as JsonPetitionTask, then push a new JsonPetitionTask.Data object. This object would contain your URL, your JSON, and any other data you need.
Setting up the AsyncTask
Something like this:
public class JsonPetitionTask extends AsyncTask<JsonPetitionTask.Data, Integer, Boolean> {
protected Boolean doInBackground(JsonPetitionTask.Data... args) {
for (int i = 0; i < args.length; i++) {
JsonPetitionTask.Data data = args[i];
// Send your JSON; check for errors, and return false if needed.
if (isCancelled()) break;
}
return true;
}
protected void onProgressUpdate(Integer... progress) {
// Show progress?
}
protected void onPostExecute(Boolean result) {
// result is your success true/false.
}
public static class Data {
public String jsonContent;
public String petitionUrl;
public Data(String content, String url) {
jsonContent = content;
petitionUrl = url;
}
}
}
Calling the JsonPetitionTask
Then you can call it like so:
JsonPetitionTask.Data data = new JsonPetitionTask.Data(myJSON, myURL);
new JsonPetitionTask().execute(data);
And voilĂ , you've executed your AsyncTask using only one class with no receivers.
Implementing a callback
Now, if you want to register a callback (something to execute that is specific to the calling code), that's a bit trickier. If this is part of what you're looking for, I'll be glad to edit this post and explain it.
To add a callback, we can use the Runnable class to execute some code after the job is done.
Firstly, we need to add a new field in the Data inner class:
public Runnable callback;
Next, before we call execute(), we need to add a new callback to our data object.
data.callback = new Runnable() {
public void run() {
// Whatever code you want to run on completion.
}
};
Third, in the JsonPetitionTask class, we need a list of things to run:
private ArrayList<Runnable> mRunnables = new ArrayList<Runnable>();
Make sure, in each iteration of the doInBackground() loop, that you do mRunnables.add(data.callback);.
Lastly, in onPostExecute(), we need to call this:
protected void onPostExecute(Boolean result) {
for (Runnable r : mRunnables)
if (r != null) r.run();
}
I do realize I didn't send result to the Runnable, however I didn't feel like implementing a new Runnable type just to handle that. If you need this, I guess that's a bit of homework for you!
The way I found the best is just simply create public class that extends AsyncTask and then you just override onPostExecute function in every activity you use it.
Example:
MyDataTask dataTask = new MyDataTask() //you can add your parameters in class constructor
{
#Override
protected void onPostExecute(Object result) //replace Object with your result type
{
MyActivity.this.doStuff(result); //use result in current activity
}
};
you can also create some custom functions to set private variables in datatask
dataTask.AddParam("user", username);
dataTask.AddParam("pass", pass);
and then just execute it with your args...
dataTask.execute(myArgs);
I have used Async task class as single class. And for every Webservice call i have used unique IntentFilter to Broadcast response.
Put that Broadcast receiver in every class. You have perfect solution.
Its working well.

How to pass variables in and out of AsyncTasks?

I haven't spent much time working with AsyncTasks in Android. I'm trying to understand how to pass variables to and from the class. The syntax:
class MyTask extends AsyncTask<String, Void, Bitmap>{
// Your Async code will be here
}
it's a little bit confusing with the < > syntax on the end of the class definition. Never seen that type of syntax before. It seems like I'm limited to only passing one value into the AsyncTask. Am I incorrect in assuming this? If I have more to pass, how do I do that?
Also, how do I return values from the AsyncTask?
It's a class and when you want to use it you call new MyTask().execute() but the actual method you use in the class is doInBackground(). So where do you actually return something?
Note: all of the information below is available on the Android Developers AsyncTask reference page. The Usage header has an example. Also take a look at the Painless Threading Android Developers Blog Entry.
Take a look at the source code for AsynTask.
The funny < > notation lets you customize your Async task. The brackets are used to help implement generics in Java.
There are 3 important parts of a task you can customize:
The type of the parameters passed in - any number you want
The type for what you use to update the progress bar / indicator
The type for what you return once done with the background task
And remember, that any of the above may be interfaces. This is how you can pass in multiple types on the same call!
You place the types of these 3 things in the angle brackets:
<Params, Progress, Result>
So if you are going to pass in URLs and use Integers to update progress and return a Boolean indicating success you would write:
public MyClass extends AsyncTask<URL, Integer, Boolean> {
In this case, if you are downloading Bitmaps for example, you would be handling what you do with the Bitmaps in the background. You could also just return a HashMap of Bitmaps if you wanted. Also remember the member variables you use are not restricted, so don't feel too tied down by params, progress, and result.
To launch an AsyncTask instantiate it, and then execute it either sequentially or in parallel. In the execution is where you pass in your variables. You can pass in more than one.
Note that you do not call doInBackground() directly. This is because doing so would break the magic of the AsyncTask, which is that doInBackground() is done in a background thread. Calling it directly as is, would make it run in the UI thread. So, instead you should use a form of execute(). The job of execute() is to kick off the doInBackground() in a background thread and not the UI thread.
Working with our example from above.
...
myBgTask = new MyClass();
myBgTask.execute(url1, url2, url3, url4);
...
onPostExecute will fire when all the tasks from execute are done.
myBgTask1 = new MyClass().execute(url1, url2);
myBgTask2 = new MyClass().execute(urlThis, urlThat);
Notice how you can pass multiple parameters to execute() which passes the multiple parameter on to doInBackground(). This is through the use of varargs (you know like String.format(...). Many examples only show the extraction of the first params by using params[0], but you should make sure you get all the params. If you are passing in URLs this would be (taken from the AsynTask example, there are multiple ways to do this):
// This method is not called directly.
// It is fired through the use of execute()
// It returns the third type in the brackets <...>
// and it is passed the first type in the brackets <...>
// and it can use the second type in the brackets <...> to track progress
protected Long doInBackground(URL... urls)
{
int count = urls.length;
long totalSize = 0;
// This will download stuff from each URL passed in
for (int i = 0; i < count; i++)
{
totalSize += Downloader.downloadFile(urls[i]);
publishProgress((int) ((i / (float) count) * 100));
}
// This will return once when all the URLs for this AsyncTask instance
// have been downloaded
return totalSize;
}
If you are going to be doing multiple bg tasks, then you want to consider that the above myBgTask1 and myBgTask2 calls will be made in sequence. This is great if one call depends on the other, but if the calls are independent - for example you are downloading multiple images, and you don't care which ones arrive first - then you can make the myBgTask1 and myBgTask2 calls in parallel with the THREAD_POOL_EXECUTOR:
myBgTask1 = new MyClass().executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR, url1, url2);
myBgTask2 = new MyClass().executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR, urlThis, urlThat);
Note:
Example
Here is an example AsyncTask that can take as many types as you want on the same execute() command. The restriction is that each type must implement the same interface:
public class BackgroundTask extends AsyncTask<BackgroundTodo, Void, Void>
{
public static interface BackgroundTodo
{
public void run();
}
#Override
protected Void doInBackground(BackgroundTodo... todos)
{
for (BackgroundTodo backgroundTodo : todos)
{
backgroundTodo.run();
// This logging is just for fun, to see that they really are different types
Log.d("BG_TASKS", "Bg task done on type: " + backgroundTodo.getClass().toString());
}
return null;
}
}
Now you can do:
new BackgroundTask().execute(this1, that1, other1);
Where each of those objects is a different type! (which implements the same interface)
I recognize that this is a late answer, but here's what I've been doing for the last while.
When I'm needing to pass in a bunch of data to an AsyncTask, I can either create my own class, pass that in and then access it's properties, like this:
public class MyAsyncTask extends AsyncTask<MyClass, Void, Boolean> {
#Override
protected Boolean doInBackground(MyClass... params) {
// Do blah blah with param1 and param2
MyClass myClass = params[0];
String param1 = myClass.getParam1();
String param2 = myClass.getParam2();
return null;
}
}
and then access it like this:
AsyncTask asyncTask = new MyAsyncTask().execute(new MyClass());
or I can add a constructor to my AsyncTask class, like this:
public class MyAsyncTask extends AsyncTask<Void, Void, Boolean> {
private String param1;
private String param2;
public MyAsyncTask(String param1, String param2) {
this.param1 = param1;
this.param2 = param2;
}
#Override
protected Boolean doInBackground(Void... params) {
// Do blah blah with param1 and param2
return null;
}
}
and then access it like this:
AsyncTask asyncTask = new MyAsyncTask("String1", "String2").execute();
Hope this helps!
Since you can pass array of objects in the square bracket, that is the best way to pass data based on which you want to do processing in the background.
You could pass the reference of your activity or the view in the Constructor and use that to pass data back into your activity
class DownloadFilesTask extends AsyncTask<URL, Integer, List> {
private static final String TAG = null;
private MainActivity mActivity;
public DownloadFilesTask(MainActivity activity) {
mActivity = activity;
mActivity.setProgressBarIndeterminateVisibility(true);
}
protected List doInBackground(URL... url) {
List output = Downloader.downloadFile(url[0]);
return output;
}
protected void onProgressUpdate(Integer... progress) {
setProgressPercent(progress[0]);
}
private void setProgressPercent(final Integer integer) {
mActivity.setProgress(100*integer);
}
protected void onPostExecute(List output) {
mActivity.mDetailsFragment.setDataList((ArrayList<Item>) output);
//you could do other processing here
}
}
Alternatively, you could just use a regular thread and usea handler to send data back to the ui thread by overriding the handlemessage function.
Passing a simple String:
public static void someMethod{
String [] variableString= {"hello"};
new MyTask().execute(variableString);
}
static class MyTask extends AsyncTask<String, Integer, String> {
// This is run in a background thread
#Override
protected String doInBackground(String... params) {
// get the string from params, which is an array
final String variableString = params[0];
Log.e("BACKGROUND", "authtoken: " + variableString);
return null;
}
}

how to create Asynctask to load sounds into a manager on a loading screen

My past two questions were short and not detailed so I'll try my best this time. I have a large soundboard with around 430 sounds. It is so big, I have to create 2 soundmanagers on some devices. Anyway, on the loading screen, I am trying to implement an AsyncTask. I generally understand its types and its 4 steps, but I do not understand the parameters. Here is a simple AsyncTask for reference.
private class DownloadFilesTask extends AsyncTask<URL, Integer, Long> {
protected Long doInBackground(URL... urls) {
}
return null;
}
protected void onProgressUpdate(Integer... progress) {
}
protected void onPostExecute(Long result) {
}
}
What I need to do in the background is add sounds to my manager like this:
SoundManager2.addSound(415, R.raw.rubber);
Please, this is my 3rd question here so if you need ANY other info, don't hesitate to ask, I'll be watching this thread for the next 20 minutes and I'll edit it with the information quickly!
In the example you give...
private class DownloadFilesTask extends AsyncTask<URL, Integer, Long> {...}
The three types URL, Integer and Long (known as Params, Progress, Result) can be anything you need them to be.
The first (URL) is the type of parameter you must pass to the .execute(<params>) method of your AsyncTask instance. More accurately when you look at the doInBackground() method you will see URL... which basically means it will accept an array of URL. Even if you only need to pass one URL you must still pass it as a single-item array
URL[] myURLs = new URL[] {<comma-separated URLs here>};
new DownloadFilesTask().execute(myURLs);
In the doInBackground(URL... urls) method you access the URLs as urls[0], urls[1] etc or something like for (URL u:urls).
The second generic type in this example (Integer) is the type expected by onProgressUpdate(Integer progress). Again this must be passed as an array. For instance if you are downloading 10 files then call it after each file has been downloaded. For example myProgress[0] = 1 to indicate one file has been successfully downloaded. This allows you to update a progress dialog of some sort.
Finally the third generic type (Long) is again used internally and is the type onDoInBackground(...) must return and is passed to onPostExecute(Long result). Note this is a single result and not an array. Depending on what your result is will depend on how onPostExecute() should behave.
As I said you can use any types including generic Void (note capital letter)...
private class MyAysncTask extends AsyncTask<Void, Void, Void>
In this case you don't pass anything to .execute() and although you can still call publishProgress() (to call onProgressUpdate()) you can't pass any data to it. Similarly, onPostExecute will not receive any actual result data.

Categories

Resources