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!
Related
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);
I have to use Async Task to do a post and a get resquest in my Server. I got an error because I was doing in android 2.3 Gingerbread, and for later versions I need AsyncTask.
I have this code here :
private class Connection extends AsyncTask {
#Override
protected Object doInBackground(Object... arg0) {
connect();
return null;
}
So, in my on create I call
new Connection().execute();
but, the problem is I have 3 function:
postData()
getData()
How can I use doInBackground(Object... arg0) with 2 diferents, functions?
Des someone know how to do it 2 times?
Thank you
There are various ways of doing it. You could create two AsyncTask subclasses, one for postData() and another for getData(). Or you could create a single subclass in which you choose which operation to do depending on a parameter passed in its constructor or as a parameter to execute(...). That said, you should never run execute() more than once for the same instance (object) of a given AsyncTask; create a different instance and call execute() on the new instance instead.
I've been researching all day trying to find out how to retrieve the values computed in the doInBackground async task. No luck at all.
I'm doing a basic HttpURLConnection request and parsing some XML data from a webpage using the DOM. I successfully store the data in two different arrays
///////////inside doInBackground:
for(int x=0; x<10; x++)
{
username[x] = element.getFirstChild().getNodeValue();
score[x] = anotherElement.getFirstChild().getNodeValue();
}
Now, all I want to do is simply output the values onto a textView.
Among many other things, I have attempted:
protected void onPostExecute(String result)
{
for (int xx = 0; xx<10; xx++)
{
theMainTextView.append(username[xx] + " scored " + score[xx] +"\n");
}
}
Nothing I have attempted works. A recurring error I'm receiving is the NullPointerException. Am I doing something dramatically incorrect? Know of any other (even obscure) methods I could try? Ignore the for loops if that helps...I've omitted a lot of code. Just assume I want to retrieve two values...a username and a score.
Edit: I should probably mention that the AsyncTask ends with return null;
Edit: apparently the code is not faulty but I had a globally declared button which was causing a null Pointer Exception. Sorry about that.
If you get a NullPointerException as stated in the question and this is all of your onPostExecute() code than the field theMainTextView must be null.
You must initialize it before starting the AsyncTask - best place to do so is in onCreate() for Activities or onCreateView() for Fragments.
Although it's not the best practice, your code should work. I think the problem comes from another part. Can you please specify what line is throwing the NullPointerException?
To retrieve values from an AsyncTask you can use listener.
First create interface listner (new file):
public interface AsyncListener {
void onAsyncFinishMethod(String params);
}
Second, use implement for your main class where you call async task (example)
public class MainActivity implements AsyncListener {
Third, create full body for listener method in your main class. You are overriding method from interface. So if you change params you will have to change too in interface. Here you will get all results after task finish and call onPostExecute.
#Override
public void onAsyncFinishMethod(String params) {
Log.d("xxx", params);
}
Fourth, set listener for your async task. It means: In your async task class create this method
public void setOnAsyncFinishedMethod(AsyncListener listener) {
this.listener = listener;
}
Make sure, your async task has private param with type that listener
private AsyncListener listener;
In onPostExecute in async task class call listener method as a last (if you don't have this method, please create it)
#Override
protected void onPostExecute(String params) {
listener.onAsyncFinishMethod(param);
}
Last step, during calling async task in your main class don't forget bind setOnAsyncFinishedMethod method to it
My Example:
private void runMyAsyncTask() {
CustomAsync async = new CustomAsync();
async.setOnAsyncFinishedMethod(this);//<<< before execute use setOnAsyncFinishedMethod
thread.execute();
}
Of course, params used in onAsyncFinishedMethod could be different than you, also onPostExecute.
I have set up an async task that will get a list of countries from a wsdl and from the result i create a bunch of country objects and add the objects to an arraylist in the country class file.
I want to be able to run this async task that will populate the array list then from another view be able to call specific indexes from the array list based on what the user has selected.
i have tried creating a class that extends AsyncTask and i have inserted the same code from the gingerbread version of the app i created which worked fine because network actions could be ran from the main thread
The type getWSDL2 must implement the inherited abstract method AsyncTask.doInBackground(Object...)
i dont have any objects to pass to this i all variables and stuff to get the wsdl data is within the async task and all the data i need from it is assigned to the arraylist from within the async task.
public class getWSDL2 extends AsyncTask {
protected void doInBackground()
{
........
}
Pass Void... as a parameter for doInBackground
protected void doInBackground(Void... params)
{
........
}
The way I understand your question you're not sure how to implement the AsyncTask because you have no need to pass values into it. All of the variables and data you need are included within the code that will execute the transaction with your server to download whatever it is you intend to display.
public class getWSDL2 extends AsyncTask {
protected Void doInBackground(Void... params) {
//All I/O code here
}
protected Void onPostExecute(){
//Anything that needs to run on the UI thread here
}
}
The general structure of the AsyncTask is listed above. The doInBackground method must contain any I/O functions while any thing you do tha touches a view, i.e. displaying the results of you're query as saved in a array list, must be called from onPostExecute, which runs on the UI thread.
From what I gather the solution is simple. Put all the code that is required for your server transaction within the doInBackground method. If you need to display the results of that transaction in a view just add a return statment to doInBackground and include the type of object/variable you will return in the varargs listed for the AsyncTask. For example if you were going to display the result of an ArrayList generated in your doInBackground method
public class getWSDL2 extends AsyncTask {
protected ArrayList<String> doInBackground(Void... params) {
//All I/O code here
return nameOfArrayListYouBuild
}
protected Void onPostExecute(ArrayList<String> whatever){
//use ArraList whatever to display your stuff
}
}
In the alternative if you don't need to display anything or run any functions on the UI thread then don't use the onPostExecute method at all.
public class getWSDL2 extends AsyncTask {
protected Void doInBackground(Void... params) {
//All I/O code here
return null
}
}
You can structure you're task so that it just uses doInBackground
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.