Why my AsyncTask doInBackground() is not passing a value to onPostExecute()? - android

when i run my code, it returns a value as "null"`
private class MessageActivityLoaderTask extends AsyncTask<Void, Void, Contentlist> {
private LinkedMultiValueMap<String, String> formData;
Activity activity;
public MessageActivityLoaderTask(Activity activity) {
this.activity = activity;
}
#Override
protected void onPreExecute() {
formData = new LinkedMultiValueMap<String, String>();
mProgress.setMessage("Please wait..");
mProgress.show();
}
#Override
protected Contentlist doInBackground(Void... params) {
String url = getString(R.string.base_url) + "/example/example1/1";
Contentlist mess = null;
try {
mess = RestUtils.exchangeFormData(url, HttpMethod.GET, formData, Contentlist.class);
} catch (Exception e) {
e.printStackTrace();
mProgress.dismiss();
}
return mess;
}
protected void onPostExecute(Contentlist result) {
if (result== null) {
Toast message = Toast.makeText(ListobjectsActivity.this, "result is empty", Toast.LENGTH_SHORT);
message.show();
} else {
ListactivityAdapter adapter = new ListactivityAdapter(this.activity, result.getContents());
ListView list = (ListView) activity.findViewById(R.id.account);
list.setAdapter(adapter);
mProgress.dismiss();
}
}`

Your AsyncTask looks like it is set up correctly, so onPostExecute() will receive the ContentList returned by doInBackgroun(). Since onPostExecute() is seeing a null, then doInBackground() is returning a null. That means that either doInBackground() is getting an exception and mess is never set to a non-null value by falling through the catch or RestUtils.exchangeFormData() is returning a null.
I suggest that you debug the code in this area to see what is really going on. It is not likely to be an AsyncTask problem.

Related

android WeakReference of activity

I have an Async Task, where I had a warning that it should be static or leaks might occur.
So I used a WeakReference like this:
private static class GetContacts extends AsyncTask<String, Void, Boolean> {
ProgressDialog dialog;
private WeakReference<Novinky> activityReference;
GetContacts(Novinky context) {
activityReference = new WeakReference<>(context);
}
#Override
protected void onPreExecute() {
// get a reference to the activity if it is still there
Novinky activity = activityReference.get();
if (activity == null || activity.isFinishing()) return;
super.onPreExecute();
dialog = new ProgressDialog(activity);
dialog.setMessage("Načítavam");
dialog.setTitle("Pripájam sa k serveru");
dialog.show();
dialog.setCancelable(false);
}
#Override
protected Boolean doInBackground(String... args) {
HttpHandler sh = new HttpHandler();
String url = "https://www...";
String jsonStr = sh.makeServiceCall(url);
if (jsonStr != null) {
try {JSONObject jsonObj = new JSONObject(jsonStr);
JSONArray actors = jsonObj.getJSONArray("result");
for (int i = 0; i < actors.length(); i++) {
JSONObject c = actors.getJSONObject(i);
Actors actor = new Actors();
actor.setLetter(c.getString("letter"));
actor.setNazov(c.getString("name"));
actor.setPerex(c.getString("perex"));
actorsList.add(actor);
}
} catch (final JSONException e) {
Novinky.this.runOnUiThread(new Runnable() {
#Override
public void run() {
Toast.makeText(Novinky.this.getApplicationContext(),
"Chyba dát: " + e.getMessage(),
Toast.LENGTH_LONG).show();
}
}); }
return true;
} else {
Novinky.this.runOnUiThread(new Runnable() {
#Override
public void run() {
Toast.makeText(Novinky.this.getApplicationContext(),
"Chyba internetového pripojenia.",
Toast.LENGTH_LONG).show();
}
});
return false;
}
}
protected void onPostExecute(Boolean result) {
// get a reference to the activity if it is still there
Novinky activity = activityReference.get();
if (activity == null || activity.isFinishing()) return;
super.onPostExecute(result);
dialog.dismiss();
adapter.notifyDataSetChanged();
}
}
Now that warning is gone, but I am still fighting with some other errors which came up due my changes.
1/ actorsList.add(actor); - in my for loop now says Non-static field 'actorsList' cannot be referenced from a static context
2/ in catch and else statement where runOnUiThread is placed I have issues with Novinky.this.runOnUiThread - cannot be referenced from a static context
If I simply replace Novinky.this with the WeakReference (activityReference) then it says class name is expected, so not sure how to correctly replace Novinky.this in those threads.
I tried also to use Novinky activity = activityReference.get(); and then use activity.runOnUiThread - this removes the error, but the definition of Novinky activity = activityReference.get(); has then warning This field leaks a context object
3/ The last issue is in my onPostExecute - adapter.notifyDataSetChanged();. The error says: Non-static field 'adapter' cannot be referenced from a static context
UPDATE: I solved it somehow and now I have no errors and the app is running, however still not sure if I solved it correctly:
For 1/ I defined static ArrayList<Actors> actorsList; in the main class.
2/ in catch and else I defined
final Novinky activity = activityReference.get();
and then:
activity.runOnUiThread
3/ in onPostExecute I used activity.adapter.notifyDataSetChanged();
You should be able to access your instance of the list the same way you access the adapter:
activityReference.get().actorsList

AsyncTask return a boolean while retrieving information from a Json

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....

Start activity is slow

I'm write a music application online.But i'm meet a problem... A new activity starts slowly when I select an item in listview...
I don't know resolve, please help me ! :(
Sorry. I'm speak English very bad :(
This is my code:
public class startNewActivity extends AsyncTask<String, Void, String> {
private Activity activity;
private String selectDoc = "div.gen img";
private String attr = "title";
private String result;
public String Quality;
public startNewActivity(Activity activity) {
this.activity = activity;
}
#Override
protected String doInBackground(String... arg0) {
nameSong = (String) lvSong.getItemAtPosition(positionId);
link = linkSong.get(Integer.valueOf(obj.toString()));
Quality = Utils.getQuality(link, selectDoc, attr, result);
Log.i("Quality", Quality);
changeLink = link.replace(".html", "_download.html").substring(15)
.replaceFirst("", "http://download")
.replace("nhac-hot", "mp3".concat("/vietnam/v-pop"));
Log.i("Change link", changeLink);
try {
//Connect internet
linkIntent = Utils.getLinkPlay(selectLinkPlay, changeLink,
afterChangeLink);
} catch (Exception e) {
Toast.makeText(getApplicationContext(),
"Server has problem... Please while for minutes",
Toast.LENGTH_SHORT).show();
}
return linkIntent;
}
#Override
protected void onPostExecute(String result) {
//i'm want help here
Intent i = new Intent(SongActivity.this, PlayMusicActivity.class);
i.putExtra("song", linkIntent);
i.putExtra("namesong", nameSong);
i.putExtra("Quality", Quality);
i.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
activity.startActivity(i);
pDialog.dismiss();
super.onPostExecute(result);
}
#Override
protected void onPreExecute() {
pDialog = ProgressDialog.show(SongActivity.this, "",
"Please wait...");
}
}
You're starting the new activity inside onPostExecute() which executes only after you've completed doInBackground(). Hence, the time delay.
Ideally, you should start the activity just after you execute your AsyncTask. The AsyncTask will continue in the background while your activity changes.

List getting cleared before AsyncTask completes

I have an AsyncTask which loads Tweets from Twitter.
I also have a PullToRefresh ListView... Whenever i pull to refresh it, the listview immediately clears and as soon as the data has been loaded, it's getting filled into the listview.
I have other ListViews in my App all with the same stuff (PullToRefresh and Async data loading...). On the other ListViews this does not happen. Only on the Twitter ListView. What am I doing wrong?
Here is my Code:
public class TwitterDownloader extends AsyncTask<Void, Void, String> {
final Handler mHandler = new Handler();
public TwitterDownloader() {
}
#Override
public void onPreExecute() {
super.onPreExecute();
}
#Override
protected String doInBackground(Void... params) {
twitter4j.Twitter twitter = new TwitterFactory().getInstance();
listTweets.clear();
List<twitter4j.Status> statuses = null;
try {
statuses = twitter.getUserTimeline(
MainActivity.TWITTER_USERNAME, new Paging(1, 50));
} catch (TwitterException e) {
e.printStackTrace();
Log.e(MainActivity.LOG_TAG, "TwitterException");
}
try {
for (twitter4j.Status status : statuses) {
listTweets.add(status.getText());
}
} catch (NullPointerException npe) {
}
return null;
}
#Override
public void onPostExecute(String unused) {
MyCustomAdapter myAdapter = new MyCustomAdapter(myContext,
R.layout.row_twitter, listTweets);
setListAdapter(myAdapter);
getListView().setTextFilterEnabled(true);
String lastUpdate = (new SimpleDateFormat(
"HH:mm")).format(new Date());
pullToRefreshView.onRefreshComplete();
pullToRefreshView.setLastUpdatedLabel(getString(R.string.last_updated) + ": "
+ lastUpdate);
}
I am not sure about this but in doInBackground method of AsyncTask, you are doing listTweets.clear();. After getting result, you are adding data to it. May be this is causing problems.
I finally fixed it by adding all my clear() statements right before I fill up my list again (which is inside a try catch).
So the new code inside my doInBackground method is:
try {
listTweets.clear();
listUsernames.clear();
listDates.clear();
listImageURLs.clear();
listURLsOfTweets.clear();
for (twitter4j.Status status : statuses) {
listTweets.add(status.getText());
listUsernames.add(status.getUser().getName());
listDates.add(android.text.format.DateFormat
.getDateFormat(getApplicationContext()).format(
status.getCreatedAt())
+ " "
+ android.text.format.DateFormat.getTimeFormat(
getApplicationContext()).format(
status.getCreatedAt()));
listImageURLs.add(status.getUser().getProfileImageURL()
.toString());
StringBuffer address = new StringBuffer();
address.append("http://twitter.com/#!/");
address.append(status.getUser().getScreenName());
address.append("/status/");
address.append(status.getId());
listURLsOfTweets.add(address.toString());
}

Passing arguments to AsyncTask, and returning results

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.

Categories

Resources