In a fragment I'm using an 'AsyncTask' to retrieve data from a URL. The main purpose of my code is to access the data (via AsyncTask) and to pass a 'JSONArray' to the fragment.
Problem is, on the fragment side, that when I check the variable that should have the result i get an error saying that the variable is null.
Here is the code:
public class MyFragment extends ListFragment {
//this is the variable that should have the result from the AsyncTask
JSONArray myResult = null;
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
(...)
//execute the asyncTask
new GetResult().execute(email, password);
(...)
}
//The AsyncTask
private class GetResult extends AsyncTask<String, Void, JSONArray> {
#Override
protected JSONArray doInBackground(String... params) {
(...)
JSONArray jsonArray = (JSONArray) json.get("customer");
return jsonArray;
}
protected void onPostExecute(JSONArray result){
(...)
//this is where I try to pass the data to the fragment
MyFragment.this.myResult = result;
}
}
}
Can someone can help me with that? Thank you in advance.
Are you using the value after postExecute method. You should know that after calling execute, your code on the main thread still runs and only after postExecute has completed, will you have the value.
Try to use this code, and make sure that your jsonstring is not null, because you won't post your complete code and I can't see if myResult variable was changed:
try {
JSONArray json = new JSONArray(jsonstring);
JSONObject json_customer = json.getJSONObject("customer");
return json_customer;
} catch (JSONException e) {
return null
}
For me it looks like problem with deserialization from String data to json's. We are lack of information what exactly data you are parsing. Consider using for this some more advanced json processing library lika Gson or Jackson. Usually its easier with them.
It sounds like you are trying to read from myResult variable before the AsyncTask finishes retrieving it. To make sure it populates properly, put this into your onPostExecute function, after this line MyFragment.this.myResult = result;:
Log.i("my result value is: ", MyFragment.this.myResult.toString())
It should print it out in the LogCat if you are retrieving it correctly, and you should be able to access that variable after that.
On a separate note, consider using Volley or Retrofit or another networking plugin to make your life easier.
Maybe you can use a clear way to transfer data back from the task to the fragment.
1) define an interface as the event listener to be called in the AsyncTask, like
public interface TaskEventListener(){
public void onTaskStarted(int messageId);
public void onTaskStopped(int messageId, int resultCode);
public void onDataReady(Object parameter);
}
2) let the fragment implement this EventListener, put the processing code in the onDataReady() function.
3) pass the fragment instance as the EventListener instance.
4) in the class extended from the AsyncTask, call the onTaskStarted() in the onPreExecute() function, call the onDataReady() and onTaskStopped() in the onPostExecute() function, and call the onTaskStopped() only in the onCancelled() function.
5) please use the weak references in the background task class to prevent crashing for referring the invalid UI component.
Related
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.
I am new to android. I have written a asynctask class which takes one string as parameter. Asynctask class has two functions doinbackground and onpostexecute. doinbackground is doing a httppost and if the post is successful it is returning a string "Success" to onpostexecute or pasing "Failed" to onpostexecute.
In Mainactivity I am calling the Asyncclass like below:
new MyAsyncTask().execute(xmlFile);
But I need to get the string that doinbackground returns in my mainactivity as based on this status I need to update a database filed. Can anyone help me on this issue.
Hypothetically I want to do the below in MainActivity
////////////////////////
Run the asyncclass by passing a string;;;
if doinbackground returns "Success" update database
else don't update
///////////////////////////
Thanks
You can use interface as a callback to the activity.
You can check blackbelts answer in the below link
How do I return a boolean from AsyncTask?
Or you can make AsyncTask an inner class of activity and get the result in onPostExecute.
You have several ways. One is using a Handler, to intercommunicate the Activity with your AsyncTask. This would involve passing the Handler object from the Activity to the AsyncTask and storing it there, so you can later use it. more on this here.
Another way is using a BroadcastReceiver. You declare it where you want to use it (i.e., where you want to receive the data, in this case in your Activity) and you use sendBroadcast from the AsyncTask to the Activity. More on this here.
There are more ways, but this ones are the most widely used.
You could probably just do your database update in the doInBackground instead of the onPostExecute that way you have your result and whether or not the http call passed.
Or you could have the AsyncTask return a class with whether or not it succeeded and the result then deal with it in onPostExecute, but you're back on the UI thread at that point and might not want to block with a db update.
private class PostResult {
boolean succeeded;
String response;
}
private class PostAsync extends AsyncTask<String, String, PostResult> {
protected PostResult doInBackground(String... xmlToPost) {
PostResult result = new PostResult();
try {
//do you httpPost... with xmlToPost[0];
result.response = "your data back from the post...";
result.succeeded = true;
//get your string result
}catch (Exception ex){
result.succeeded = false;
}
// I would update the db right here,
// since it's still on the background thread
return result;
}
protected void onPostExecute(PostResult result) {
//you're back on the ui thread...
if (result.succeeded){
}
}
}
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'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.
I am a newbie in Android development. Now I am trying to parse. I have got many tutorials for parsing XML. But I would like to know parse XML asynchronously. I have found somewhere, xml can be loaded asynchronously using AsyncTask. Can anybody help me to find it out.
Thanks in advance
Here's a tutorial for using AsyncTask:
http://droidapp.co.uk/?p=177
And one for parsing RSS / XML:
http://droidapp.co.uk/?p=166
You need to call your parse function in doInBackground in the AsyncTask.
public class _StackOverflowActivity extends Activity {
/** Called when the activity is first created. */
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
String yourXmlString = "<put your xml String here>";
ParseXMLTask parseXMLTask = new ParseXMLTask();
parseXMLTask.execute(yourXmlString);
}
class ParseXMLTask extends AsyncTask<String, Void, Void> {
#Override
protected Void doInBackground(String... params) {
String yourXml = params[0];
//Parse your xml here
return null;
}
#Override
protected void onPostExecute(Void result) {
super.onPostExecute(result);
//do something after parsing is done
}
}
}
First, you have to extend the class AsyncTask. In my example I named it ParseXMLTask.
AsyncTask requires you to implement one method which is "doInBackground". doInBackground runs in a separate thread, put your code for parsing the xml there.
After the thread finishes, onPostExecute is called. onPostExecute runs in your main thread, you can use this if you wish to perform something after doInBackground finishes
To use ParseXMLTask, you have to instantiate it to an object. Then run the command .execute(). You can pass objects in execute similar to what I have done parseXMLTask.execute(yourXmlString); . You can pass as many variables as you like and be sure to handle them in doInBackground similar to String yourXml = params[0]; . If you have a second variable passed in .execute say... parseXml.execute(yourXmlString, my2ndVariable); , handle it in doInBackground through
String yourXml = params[0];
String the2ndVariable = params[1];
When you call .execute you tell AsyncTask to run whatever code you have placed in doInBackground in a separate thread.