I need to pass the async task result to the calling class. I have created a separate ASync class which is called from other classes. I am passing the response from Async task in "Post Execute" method to calling class method but getting null point exception. Below is my calling method in
public boolean getCategories() {
serUri = "categories.json";
WebServiceAsyncTask webServiceTask = new WebServiceAsyncTask();
webServiceTask.execute(serUri,this);
return true;
}
The method to be executed with result from below aysnc task is
public void writeJSONArray(final JSONArray result)
{
try {
for (int i=0; i<result.length();i++){
JSONObject c = result.getJSONObject(i);
String name = c.getString("catname");
}
} catch (JSONException e) {
e.printStackTrace();
}
}
WebServiceAsyncTask Class:
public class WebServiceAsyncTask extends AsyncTask<Object,Void,JSONArray> {
ROMSjson roms;
private static JSONArray json = null;
private Context context = null;
protected JSONArray doInBackground(Object... params) {
// TODO Auto-generated method stub
String serviceUrl = (String) params[0];
final HTTPHelper httph = new HTTPHelper(serviceUrl,context);
if(serviceUrl.equalsIgnoreCase("categories.json")) {
json = httph.fetch();
}else if(serviceUrl.equalsIgnoreCase("categories/create"))
{
}
return json;
}
#Override
protected void onPostExecute(JSONArray result) { // invoked on the ui thread
roms.writeJSONArray(result);
super.onPostExecute(result);
}
I am getting null point exception when roms.writeJSONArray(result) is called. The result is correctly received before this command. I checked with Log statement. Also if I write the writeJSONArray method in my Async class instead of calling class, all works fine.
I am not sure if I am missing something in passing the result or while calling methods. Please advise. Thanks.
null pointer exception
because roms is null
you are declaring ROMSjson roms; inside WebServiceAsyncTask but not initializing it !
and using it inside `onPostExecute(JSONArray result)
roms.writeJSONArray(result);` // here roms in null
so initialize roms before using it !
Here is the problem:
else if(serviceUrl.equalsIgnoreCase("categories/create"))
{
// if it falls to this condition then your json object appears to be null
}
Hope this helps.
Interface is the best way for passing data between classes.
create a public interface
public interface WebCallListener{
void onCallComplete(JSONArray result);
}
what to do in your class?
public class WebServiceAsyncTask extends AsyncTask<Object,Void,JSONArray> {
ROMSjson roms;
private static JSONArray json = null;
private Context context = null;
//update
private WebCallListener local;
public WebServiceAsyncTask(WebCallListener listener){
local=listener;
}
/////
protected JSONArray doInBackground(Object... params) {
// TODO Auto-generated method stub
String serviceUrl = (String) params[0];
final HTTPHelper httph = new HTTPHelper(serviceUrl,context);
if(serviceUrl.equalsIgnoreCase("categories.json")) {
json = httph.fetch();
}else if(serviceUrl.equalsIgnoreCase("categories/create"))
{
}
return json;
}
#Override
protected void onPostExecute(JSONArray result) { // invoked on the ui thread
//update
super.onPostExecute(result);
local.onCallComplete(result);
}
From Your Calling class.
public class CallingClass extends Activity{
protecte void oncreate(Bundle b){
new WebServiceAsyncTask(new WebCallListener() {
#Override
public void onCallComplete(JSONArray result) {
//play with your response
}
});
}
}
Related
I know this question has been asked a lot but I still can't figure out how on my code. I'm trying to get values out of this block of code:
private void getAnswerKey(){
class GetAnswerKey extends AsyncTask<Void, Void, String> {
#Override
protected void onPreExecute() {
super.onPreExecute();
}
#Override
protected void onPostExecute(String s) {
super.onPostExecute(s);
JSON_STRING = s;
showAnswerKey();
}
#Override
protected String doInBackground(Void... params) {
RequestHandler rh = new RequestHandler();
String s = rh.sendGetRequest(Configuration.URL_GET_ANSWER);
return s;
}
}
GetAnswerKey gA = new GetAnswerKey();
gA.execute();
}
private void showAnswerKey () {
correctAnswers = new ArrayList<Integer>();
JSONObject jsonObject = null;
try {
jsonObject = new JSONObject(JSON_STRING);
JSONArray result = jsonObject.getJSONArray(Configuration.TAG_JSON_ARRAY);
for (int i = 0; i < result.length(); i++) {
JSONObject jo = result.getJSONObject(i);
int answerKey = jo.getInt(Configuration.TAG_ANSWERKEY);
correctAnswers.add(answerKey);
System.out.println((i + 1) + "a. " + options[correctAnswers.get(i)]); //data are there
}
} catch (JSONException e) {
e.printStackTrace();
}
}
How do I access correctAnswers arrayList on my main activity? correctAnswers itself isn't empty in this code, but when I tried accessing it on other method, it's null. I've tried passing data to other method. Still return null. I have the arrayList as global variable. Any ideas how??
Like suvojit_007 might have correctly assumed, you may be attempting to access the arraylist before it is populated..
You can use interfaces. Create your interface...
public interface ResponseInterface {
public void getResponse(String data);
}
In your AsyncTask declare your interface
private ResponseInterface responseInterface;
Create a constructor within the AsyncTask with the interface as a parameter
public GetAnswerKey(ResponseInterface responseInterface) {
this.responseInterface = responseInterface;
}
Within your onPostExecute, call the interface
#Override
protected void onPostExecute(String s) {
super.onPostExecute(s);
responseInterface.getResponse(s);
}
... and finally when executing your AsyncTask, do this...
new GetAnswerKey(new ResponseInterface() {
#Override
public void getResponse(String data) {
// do whatever you want with your answers here.
// Also, whatever function that is accessing the
// arrayList, call it here, that way you avoid any
// possibility of the arrayList being null
}
}).execute();
I want to check if a user is registered or not in a database, and if it is get the information of the user.
Normally, when I retrieve the information from the server, I put in the Json a variable saying if the user exists or not. Then in onPostExecute(Void result) i treat the Json, so i don't need the AsyncTask to return any value.
Before I was calling the AsyncTask as follows:
task=new isCollectorRegistered();
task.execute();
But now i'm trying a different approach. I want my asynktask to just return a boolean where i called the AsyncTask.
the AsyncTask looks as follows:
public class isCollectorRegistered extends AsyncTask<Void, Void, Void> {
private static final String TAG_SUCCESS = "success";
int TAG_SUCCESS1;
private static final String TAG_COLLECTOR = "collector";
public String collector;
JSONArray USER = null;
JSONObject jObj = null;
#Override
protected void onPreExecute() {
super.onPreExecute();
}
#Override
protected Void doInBackground(Void... params) {
// Checks on the server if collector is registered
try {
jObj = ServerUtilities.UserRegistered(context, collector);
return null;
} finally {
return null;
}
}
#Override
protected void onPostExecute(Void result) {
try {
String success = jObj.getString(TAG_SUCCESS);
Log.d(TAG_COLLECTOR, "Final Info: " + success);
//This if sees if user correct
if (Objects.equals(success, "1")){
//GOOD! THE COLLECTOR EXISTS!!
}
} catch (JSONException e) {
e.printStackTrace();
Log.d(TAG_COLLECTOR, "JSON parsing didn't work");
}
}
}
I have checked several posts, but I still havent found out the way to retrieve the boolean where I call the Asynktask, something like this :
task=new isCollectorRegistered();
task.execute();
boolean UserRegistered = task.result();
What would be the right approach? Any help would be appreciated
To use AsyncTask you must subclass it. AsyncTask uses generics and varargs. The parameters are the following AsyncTask <TypeOfVarArgParams , ProgressValue , ResultValue> .
An AsyncTask is started via the execute() method.
The execute() method calls the doInBackground() and the onPostExecute() method.
TypeOfVarArgParams is passed into the doInBackground() method as input, ProgressValue is used for progress information and ResultValue must be returned from doInBackground() method and is passed to onPostExecute() as a parameter.
In your case you are passing Void to your AsyncTask : isCollectorRegistered extends AsyncTask<Void, Void, Void> so you can't get your result from the thread.
please read this tutorial to a deep understand of the AsyncTask in Android
I think the following is exactly what you were looking for, Alvaro...NOTE: I tweaked your code to make it more sensible, but I tried to stick to as much of your original code as possible...
public class RegisterCollector extends AsyncTask<String, Void, Boolean> {
private static final String TAG_SUCCESS = "success";
private static final String TAG_COLLECTOR = "collector";
int TAG_SUCCESS1;
String[] strArray;
JSONArray USER = null;
JSONObject jObj = null;
public String collector;
private AppCompatActivity mAct; // Just incase you need an Activity Context inside your AsyncTask...
private ProgressDialog progDial;
// Pass data to the AsyncTask class via constructor -> HACK!!
// This is a HACK because you are apparently only suppose to pass data to AsyncTask via the 'execute()' method.
public RegisterCollector (AppCompatActivity mAct, String[] strArray) {
this.mAct = mAct;
this.strArray = strArray;
}
#Override
protected void onPreExecute() {
super.onPreExecute();
// AHAH!! - So we do need that Activity Context after all...*TISK* *TISK* # Google **sigh**.
progDial = ProgressDialog.show(mAct, "Please wait...", "Fetching the strawberries & cream", true, false);
}
#Override
protected Boolean doInBackground(String... params) {
// Checks on the server if collector is registered
try {
jObj = ServerUtilities.UserRegistered(context, collector);
return true; // return whatever Boolean you require here.
} finally {
return false; // return whatever Boolean you require here.
}
}
#Override
protected void onPostExecute(Boolean result) {
super.onPostExecute(result);
progDial.dismiss();
try {
String success = jObj.getString(TAG_SUCCESS);
Log.d(TAG_COLLECTOR, "Final Info: " + success);
// This 'if' block checks if the user is correct...
if (Objects.equals(success, "1")){
//GOOD! THE COLLECTOR EXISTS!!
}
// You can then also use the Boolean result here if you need to...
if (result) {
// GOOD! THE COLLECTOR EXISTS!!
} else {
// Oh my --> We need to try again!! :(
}
} catch (JSONException e) {
e.printStackTrace();
Log.d(TAG_COLLECTOR, "JSON parsing didn't work");
Toast.makeText(mAct, "JSON parsing FAILED - Please try again.", Toast.LENGTH_LONG).show();
}
}
}
...then if you want to use the generated Boolean data outside the AsyncTask class try the following:.
RegisterCollector regisColctr = new RegisterCollector((AppCompatActivity) this, String[] myStrArry);
AsyncTask<String, Void, Boolean> exeRegisColctr = regisColctr.execute("");
Boolean isColctrRegistered = false;
try {
isColctrRegistered = exeRegisColctr.get(); // This is how you FINALLY 'get' the Boolean data outside the AsyncTask...-> VERY IMPORTANT!!
} catch (InterruptedException in) {
in.printStackTrace();
} catch (ExecutionException ex) {
ex.printStackTrace();
}
if (isColctrRegistered) {
// Do whatever tasks you need to do here based on the positive (i.e. 'true') AsyncTask Bool result...
} else {
// Do whatever tasks you need to do here based on the negative (i.e. 'false') AsyncTask Bool result...
}
There you go - I think this is what you were looking for (originally). I always use this approach whenever I need Async data externally, and it has yet to fail me....
I have called an async task from my button click.In the doInBackground I have called an API and It is returning me a Json object.I want to pass the Json object to another activity on the button click.How can I can get the return Json object value so that I can send it to other activity.
Thanks.
Create Interface
public interface Listener {
void success(BaseModel baseModel);
void fail(String message);
}
Create Base model class
public class BaseModel implements Serializable {
private static final long serialVersionUID = 1L;
}
Call below method inside your onClick mehtod.
protected void userLoginData(final String userName) {
// if you want to pass multiple data to server like string or json you can pass in this constructor
UserLoginLoader userLoginLoader = new UserLoginLoader(LoginActivity.this, userName, "1234567899", new Listener() {
#Override
public void success(BaseModel baseModel) {
// here you got response in object you can use in your activity
UserLoginModel userLoginModel = (UserLoginModel) baseModel;
// you can get data from user login model
}catch(Exception exception){
exception.printStackTrace();
Utils.showAlertDialog(LoginActivity.this, "Server is not responding! Try Later.");
}
}
#Override
public void fail(String message) {
}
});
userLoginLoader.execute();
}
:- User Login Loader class
public class UserLoginLoader extends AsyncTask<String, Void, Boolean> {
private Dialog dialog;
private Listener listner;
private String deviceId;
Activity activity;
String message;
String userName;
boolean checkLoginStatus;
public UserLoginLoader(Activity activity,String userName, String deviceId, Listener listener) {
this.listner = listener;
this.userName =userName;
this.activity = activity;
this.deviceId = deviceId;
}
#Override
protected Boolean doInBackground(String... arg0) {
//User login web service is only for making connection to your API return data into message string
message = new UserLoginWebService().getUserId(userName, deviceId);
if (message != "null" && !message.equals("false")) {
return true;
}
return false;
}
#Override
protected void onPreExecute() {
super.onPreExecute();
dialog = new Dialog(activity, R.style.CustomDialogTheme);
dialog.setContentView(R.layout.progress);
dialog.setCancelable(false);
dialog.show();
}
#Override
protected void onPostExecute(Boolean result) {
super.onPostExecute(result);
BaseModel baseModel = null;
if (!message.equals("null") && (!message.equals("false")) )
baseModel = parseData(message, result);
if (dialog.isShowing()) {
dialog.dismiss();
dialog.cancel();
dialog = null;
}
if (listner != null) {
if (result && baseModel != null)
listner.success(baseModel);
else
listner.fail("Server not responding! Try agian.");
} else
listner.fail("Server not responding! Try agian.");
}
//call parser for parsing data return data from the parser
private BaseModel parseData(String responseData, Boolean success) {
if (success == true && responseData != null
&& responseData.length() != 0) {
UserLoginParser loginParser = new UserLoginParser(responseData);
loginParser.parse();
return loginParser.getResult();
}
return null;
}
}
This is you Login parser class
public class UserLoginParser {
JSONObject jsonObject;
UserLoginModel userLoginModel;
/*stored data into json object*/
public UserLoginParser(String data) {
try {
jsonObject = new JSONObject(data);
} catch (JSONException e) {
Log.d("TAG MSG", e.getMessage());
e.printStackTrace();
}
}
public void parse() {
userLoginModel = new UserLoginModel();
try {
if (jsonObject != null) {
userLoginModel.setUser_name(jsonObject.getString("user_name")== null ? "": jsonObject.getString("user_name"));
userLoginModel.setUser_id(jsonObject.getString("user_id") == null ? "" : jsonObject.getString("user_id"));
userLoginModel.setFlag_type(jsonObject.getString("flag_type") == null ? "" : jsonObject.getString("flag_type"));
} else {
return;
}
} catch (Exception exception) {
exception.printStackTrace();
}
}
/*return ship name list which is stored into model */
public UserLoginModel getResult() {
return userLoginModel;
}
}
Write a callback method in the Activity that takes in the argument that you wish to pass from AsyncTask to that Activity. Send reference to the Activity to AysncTask while creating it. From doInBackground() method make a call to this callback method with the data your API returns.
Code would be something like -
public class TestAsyncTask extends AsyncTask<Integer, Integer, String[]> {
Activity myActivity;
public TestAsyncTask(Activity activity) {
this.myActivity = activity;
}
#Override
protected String[] doInBackground(Integer... params) {
String data = yourApi();
myActivity.callback(data);
}
}
public class MyActivity extends Activity {
#Override
protected void onCreate(Bundle savedInstanceState) {
new TestAsyncTask(this).execute(someId);
}
public void callback(String data) {
//process data
}
}
Just for the record you can directly get return value from doInBackground() method by calling get() on it.
String data = new TestAsyncTask(this).execute(someId).get();
But note this may block your UI thread as it will wait for the doInBackground() method to complete it's execution.
I was calling a class which was performing network operations on the main thread, causing my app to blow up on more recent devices. So I've tried moving the call to the class into a AsyncTask inner class in my main activity. However now i'm getting null reference expections.
Here's my AsyncTask:
private class RetreiveAmazonNodesXML extends AsyncTask {
private Exception exception;
#Override
protected Object doInBackground(Object... params) {
try {
childrenBrowseNodesXml = new Amazon(browseNodeId, locality);
} catch (Exception e) {
this.exception = e;
}
return null;
}
}
And here's where I call it in my activity:
RetreiveAmazonNodesXML test = new RetreiveAmazonNodesXML();
test.execute();
parseXmlFile(childrenBrowseNodesXml.getBrowseNodesXML());
childrenBrowseNodesXml isn't getting updated and returning null. I know my Amazon class works fine so its something im doing with AsyncTask, but I have no idea?
Use callback for get result from async task. Here interface callback class:
public interface Callback {
public void onSuccess(Object data);
public void onError(String errorMsg);
}
And create instance this class and implement its:
final Callback resCallback = new Callback() {
#Override
public void onSuccess(Object data) {
parseXmlFile(data);
}
#Override
public void onError(String errorMsg) {
//show error with Alert or Toast
}
};
And create asynctask class with your callback:
RetreiveAmazonNodesXML test = new RetreiveAmazonNodesXML(resCallback);
test.execute(yourObjectsParams);
Write asynctask class like this:
private class RetreiveAmazonNodesXML extends AsyncTask {
private Callback responderCallback;
private Exception exception;
public GeneralHttpTask(Callback callback){
this.responderCallback = callback;
}
#Override
protected Object doInBackground(Object... params) {
try {
Amazon childrenBrowseNodesXml = new Amazon(browseNodeId, locality);
return childrenBrowseNodesXml;
} catch (Exception e) {
this.exception = e;
}
return null;
}
#Override
protected void onPostExecute(Object result) {
if(result != null) {
responderCallback.onSuccess(result);
} else {
responderCallback.onError(exception);
}
}
}
It is because you're trying to use the value that AsyncTask hasn't returned, as AsyncTask is running asyncronously.
You should put parseXmlFile(childrenBrowseNodesXml.getBrowseNodesXML()); into your AsyncTask's onPostExecute() method, like this:
private class RetreiveAmazonNodesXML extends AsyncTask {
private Exception exception;
#Override
protected Object doInBackground(Object... params) {
try {
childrenBrowseNodesXml = new Amazon(browseNodeId, locality);
} catch (Exception e) {
this.exception = e;
}
return null;
}
#Override
protected void onPostExecute(Object obj) {
parseXmlFile(childrenBrowseNodesXml.getBrowseNodesXML());
}
}
Also, return null in doInBackground method may not be a good manner, the stuff that doInBackground returns will be passed as a parameter to onPostExecute() method automatically by AsyncTask.
For more about the AsyncTask, please refer to the Android Developers: AsyncTask
The problem is, that you create a background thread (AsyncTask) that fills the childrenBrowseNodesXml after a while (when it's actually executed), but you try to use it immediately in your activity code.
Move your parseXMLFile to onPostExecute(Void result) method of AsyncTask instead.
I have an application that does some long calculations, and I would like to show a progress dialog while this is done. So far I have found that I could do this with threads/handlers, but didn't work, and then I found out about the AsyncTask.
In my application I use maps with markers on it, and I have implemented the onTap function to call a method that I have defined. The method creates a dialog with Yes/No buttons, and I would like to call an AsyncTask if Yes is clicked. My question is how to pass an ArrayList<String> to the AsyncTask (and work with it there), and how to get back a new ArrayList<String> like a result from the AsyncTask?
The code of the method looks like this:
String curloc = current.toString();
String itemdesc = item.mDescription;
ArrayList<String> passing = new ArrayList<String>();
passing.add(itemdesc);
passing.add(curloc);
ArrayList<String> result = new ArrayList<String>();
new calc_stanica().execute(passing,result);
String minim = result.get(0);
int min = Integer.parseInt(minim);
String glons = result.get(1);
String glats = result.get(2);
double glon = Double.parseDouble(glons);
double glat = Double.parseDouble(glats);
GeoPoint g = new GeoPoint(glon, glat);
String korisni_linii = result.get(3);
So, as you see, I would like to send the string array list "passing" to the AsyncTask, and to get the "result" string array list back from it. And the calc_stanica AssycTask class looks like this:
public class calc_stanica extends AsyncTask<ArrayList<String>, Void, ArrayList<String>> {
ProgressDialog dialog;
#Override
protected void onPreExecute() {
dialog = new ProgressDialog(baraj_mapa.this);
dialog.setTitle("Calculating...");
dialog.setMessage("Please wait...");
dialog.setIndeterminate(true);
dialog.show();
}
protected ArrayList<String> doInBackground(ArrayList<String>... passing) {
//Some calculations...
return something; //???
}
protected void onPostExecute(Void unused) {
dialog.dismiss();
}
So my question is how to get the elements of the "passing" array list in the AsyncTask doInBackground method (and use them there), and how to return an array list to use in the main method (the "result" array list)?
Change your method to look like this:
String curloc = current.toString();
String itemdesc = item.mDescription;
ArrayList<String> passing = new ArrayList<String>();
passing.add(itemdesc);
passing.add(curloc);
new calc_stanica().execute(passing); //no need to pass in result list
And change your async task implementation
public class calc_stanica extends AsyncTask<ArrayList<String>, Void, ArrayList<String>> {
ProgressDialog dialog;
#Override
protected void onPreExecute() {
dialog = new ProgressDialog(baraj_mapa.this);
dialog.setTitle("Calculating...");
dialog.setMessage("Please wait...");
dialog.setIndeterminate(true);
dialog.show();
}
protected ArrayList<String> doInBackground(ArrayList<String>... passing) {
ArrayList<String> result = new ArrayList<String>();
ArrayList<String> passed = passing[0]; //get passed arraylist
//Some calculations...
return result; //return result
}
protected void onPostExecute(ArrayList<String> result) {
dialog.dismiss();
String minim = result.get(0);
int min = Integer.parseInt(minim);
String glons = result.get(1);
String glats = result.get(2);
double glon = Double.parseDouble(glons);
double glat = Double.parseDouble(glats);
GeoPoint g = new GeoPoint(glon, glat);
String korisni_linii = result.get(3);
}
UPD:
If you want to have access to the task starting context, the easiest way would be to override onPostExecute in place:
new calc_stanica() {
protected void onPostExecute(ArrayList<String> result) {
// here you have access to the context in which execute was called in first place.
// You'll have to mark all the local variables final though..
}
}.execute(passing);
Why would you pass an ArrayList??
It should be possible to just call execute with the params directly:
String curloc = current.toString();
String itemdesc = item.mDescription;
new calc_stanica().execute(itemdesc, curloc)
That how varrargs work, right?
Making an ArrayList to pass the variable is double work.
I sort of agree with leander on this one.
call:
new calc_stanica().execute(stringList.toArray(new String[stringList.size()]));
task:
public class calc_stanica extends AsyncTask<String, Void, ArrayList<String>> {
#Override
protected ArrayList<String> doInBackground(String... args) {
...
}
#Override
protected void onPostExecute(ArrayList<String> result) {
... //do something with the result list here
}
}
Or you could just make the result list a class parameter and replace the ArrayList with a boolean (success/failure);
public class calc_stanica extends AsyncTask<String, Void, Boolean> {
private List<String> resultList;
#Override
protected boolean doInBackground(String... args) {
...
}
#Override
protected void onPostExecute(boolean success) {
... //if successfull, do something with the result list here
}
}
I dont do it like this. I find it easier to overload the constructor of the asychtask class ..
public class calc_stanica extends AsyncTask>
String String mWhateveryouwantToPass;
public calc_stanica( String whateveryouwantToPass)
{
this.String mWhateveryouwantToPass = String whateveryouwantToPass;
}
/*Now you can use whateveryouwantToPass in the entire asynchTask ... you could pass in a context to your activity and try that too.*/ ... ...
You can receive returning results like that:
AsyncTask class
#Override
protected Boolean doInBackground(Void... params) {
if (host.isEmpty() || dbName.isEmpty() || user.isEmpty() || pass.isEmpty() || port.isEmpty()) {
try {
throw new SQLException("Database credentials missing");
} catch (SQLException e) {
e.printStackTrace();
}
}
try {
Class.forName("org.postgresql.Driver");
} catch (ClassNotFoundException e) {
e.printStackTrace();
}
try {
this.conn = DriverManager.getConnection(this.host + ':' + this.port + '/' + this.dbName, this.user, this.pass);
} catch (SQLException e) {
e.printStackTrace();
}
return true;
}
receiving class:
_store.execute();
boolean result =_store.get();
Hoping it will help.