I am working on android app and facing a problem. The problem is that onPostExecute does not execute everytime event doInBackground execute successfully and return true. My code is given below. Please help me I am in big trouble.
class JSONAsyncTask extends AsyncTask<String, Void, Boolean> {
#Override
protected void onPreExecute() {
super.onPreExecute();
msgtouser.setText("Wait we are fetching HOT DEALS...");
}
#Override
protected Boolean doInBackground(String... urls) {
Boolean retValue = false;
try {
HttpResponse response = null;
String CSRFTOKEN = "";
// Create a new HttpClient and Post Header
DefaultHttpClient httpClient = new DefaultHttpClient();
// Access POST route using CSRFTOKEN
HttpPost httppost = new HttpPost(urls[0]);
try {
// Add your data
List<NameValuePair> nameValuePairs = new ArrayList<NameValuePair>(2);
nameValuePairs.add(new BasicNameValuePair("_token", CSRFTOKEN));
nameValuePairs.add(new BasicNameValuePair("uid", urls[1]));
httppost.setEntity(new UrlEncodedFormEntity(nameValuePairs));
// Execute HTTP Post Request
response = httpClient.execute(httppost);
} catch (Exception e) {
ccode.ErrorReporting(e);
}
int status = response.getStatusLine().getStatusCode();
if (status == 200) {
HttpEntity entity = response.getEntity();
String data = EntityUtils.toString(entity);
JSONObject jsono = new JSONObject(data);
JSONArray jarray = jsono.getJSONArray("hotdeal");
for (int i = 0; i < jarray.length(); i++) {
JSONObject object = jarray.getJSONObject(i);
HotDeals objHD = new HotDeals();
objHD.setId(object.getInt("offid"));
objHD.setName(object.getString("line1"));
objHD.setLocation(object.getString("line3"));
objHD.setDistance(object.getString("dist"));
objHD.setOffer(object.getString("line2"));
objHD.setImage(object.getString("ban"));
dealsList.add(objHD);
}
retValue = true;
}
} catch (Exception e) {
ccode.ErrorReporting(e);
}
return retValue;
}
#Override
protected void onPostExecute(Boolean result) {
super.onPostExecute(result);
dialog.cancel();
// adapter.notifyDataSetChanged();
if (result == false && AppConstants.ISDEBUG) {
Toast.makeText(getActivity().getApplicationContext(), "Hot Deals : Network Error", Toast.LENGTH_LONG)
.show();
} else {
if (dealsList.isEmpty()) {
msgtouser.setText("Sorry, there are no HOT DEALS for the location selected by you");
} else {
msgtouser.setVisibility(View.GONE);
ListView listview = (ListView) rootView.findViewById(R.id.listhd);
adapter = new HotDealsAdapter(HotDealsFragment.this.getActivity(), R.layout.hotdeals_row,
dealsList);
listview.setAdapter(adapter);
}
}
}
}
you don't need to call super.onPostExecute() (not sure if it could be causing problems, but isn't needed) If this isn't the problem then below...
I "think" I know what the problem is... and we've ran into it before... IF this is happening when you rotate the phone (or any other hardware change)...
Then the problem is that the return value of the doInBackground() doesn't get actually passed to the onPostExecute() and you will get a null passed in. (if the hardware change happened during the doInBackground())
However, that doesn't appear to be 'exactly' what you are having from your description. 'onPostExecute()' not running at all is odd. You should put a logcat statement as the very first thing in the method and see if that gets logged.
Because 'false' is the default value of boolean so it could be what you are describing where you don't have the 'else' part ever run, but you should be getting the toast then...
So log in two places (1) just before the return of doInBackground and (2) at the very beginning of the onPostExecute() and see if the values 'agree'
Related
I am trying to create a Login function so i can verify the users. I pass the Username , Password variables to AsyncTask class but i don't know hot to get results in order to use them. Any help? (I am posting part of the source code due to website restrictions)
btnLogin.setOnClickListener(new OnClickListener() {
#Override
public void onClick(View v) {
if(txtUsername.getText().toString().trim().length() > 0 && txtPassword.getText().toString().trim().length() > 0)
{
// Retrieve the text entered from the EditText
String Username = txtUsername.getText().toString();
String Password = txtPassword.getText().toString();
/*Toast.makeText(MainActivity.this,
Username +" + " + Password+" \n Ready for step to post data", Toast.LENGTH_LONG).show();*/
String[] params = {Username, Password};
// we are going to use asynctask to prevent network on main thread exception
new PostDataAsyncTask().execute(params);
// Redirect to dashboard / home screen.
login.dismiss();
}
else
{
Toast.makeText(MainActivity.this,
"Please enter Username and Password", Toast.LENGTH_LONG).show();
}
}
});
Then i use the AsynkTask to do the check but do not know how to get the results and store them in a variable. Any help?
public class PostDataAsyncTask extends AsyncTask<String, String, String> {
protected void onPreExecute() {
super.onPreExecute();
// do stuff before posting data
}
#Override
protected String doInBackground(String... params) {
try {
// url where the data will be posted
String postReceiverUrl = "http://server.com/Json/login.php";
Log.v(TAG, "postURL: " + postReceiverUrl);
String line = null;
String fail = "notok";
// HttpClient
HttpClient httpClient = new DefaultHttpClient();
// post header
HttpPost httpPost = new HttpPost(postReceiverUrl);
// add your data
List<NameValuePair> nameValuePairs = new ArrayList<NameValuePair>(2);
nameValuePairs.add(new BasicNameValuePair("UserName", params[0]));
nameValuePairs.add(new BasicNameValuePair("Password", params[1]));
httpPost.setEntity(new UrlEncodedFormEntity(nameValuePairs));
// execute HTTP post request
HttpResponse response = httpClient.execute(httpPost);
HttpEntity resEntity = response.getEntity();
line = resEntity.toString();
Log.v(TAG, "Testing response: " + line);
if (resEntity != null) {
String responseStr = EntityUtils.toString(resEntity).trim();
Log.v(TAG, "Response: " + responseStr);
Intent Hotels_btn_pressed = new Intent(MainActivity.this, Hotels.class);
startActivity(Hotels_btn_pressed);
// you can add an if statement here and do other actions based on the response
Toast.makeText(MainActivity.this,
"Error! User does not exist", Toast.LENGTH_LONG).show();
}else{
finish();
}
} catch (NullPointerException e) {
e.printStackTrace();
} catch (Exception e) {
e.printStackTrace();
}
return null;
}
#Override
protected void onPostExecute(String lenghtOfFile) {
// do stuff after posting data
}
}
Not the best code refactoring, but just to give you a hint.
I would create an interface (lets call it 'LogInListener'):
public interface LoginListener {
void onSuccessfulLogin(String response);
void onFailedLogin(String response);
}
The 'MainActivity' class would implement that interface and set itself as a listener the 'PostDataAsyncTask'. So, creating the async task from the main activity would look like this:
String[] params = {Username, Password};
// we are going to use asynctask to prevent network on main thread exception
PostDataAsyncTask postTask = new PostDataAsyncTask(this);
postTask.execute(params);
I would move 'PostDataAsyncTask' class into a new file:
public class PostDataAsyncTask extends AsyncTask<String, String, String> {
private static final String ERROR_RESPONSE = "notok";
private LoginListener listener = null;
public PostDataAsyncTask(LoginListener listener) {
this.listener = listener;
}
#Override
protected String doInBackground(String... params) {
String postResponse = "";
try {
// url where the data will be posted
String postReceiverUrl = "http://server.com/Json/login.php";
// HttpClient
HttpClient httpClient = new DefaultHttpClient();
// post header
HttpPost httpPost = new HttpPost(postReceiverUrl);
// add your data
List<NameValuePair> nameValuePairs = new ArrayList<NameValuePair>(2);
nameValuePairs.add(new BasicNameValuePair("UserName", params[0]));
nameValuePairs.add(new BasicNameValuePair("Password", params[1]));
httpPost.setEntity(new UrlEncodedFormEntity(nameValuePairs));
// execute HTTP post request
HttpResponse response = httpClient.execute(httpPost);
HttpEntity resEntity = response.getEntity();
postResponse = EntityUtils.toString(resEntity).trim();
} catch (NullPointerException e) {
e.printStackTrace();
} catch (Exception e) {
e.printStackTrace();
}
return postResponse;
}
#Override
protected void onPostExecute(String postResponse) {
if (postResponse.isEmpty() || postResponse.equals(ERROR_RESPONSE) ) {
listener.onFailedLogin(postResponse);
} else {
listener.onSuccessfulLogin(postResponse);
}
}
}
So, 'doInBackground' returns the response to 'onPostExecute' (which runs on the UI thread), and 'onPostExecute' routes the result (success or failure) to the MainActivity, which implements the 'LogInListener' methods:
#Override
public void onSuccessfulLogin(String response) {
// you have access to the ui thread here - do whatever you want on suscess
// I'm just assuming that you'd like to start that activity
Intent Hotels_btn_pressed = new Intent(this, Hotels.class);
startActivity(Hotels_btn_pressed);
}
#Override
public void onFailedLogin(String response) {
Toast.makeText(MainActivity.this,
"Error! User does not exist", Toast.LENGTH_LONG).show();
}
I just assumed that that's what you wanted to do on success: start a new activity, and show a toast on fail.
i am developing an android app which i have to integrate with backend(developed in java and spring). Which will be the best way to integrate either WebServices or through http(JSON)..?
Thanks in advance.
To get a JSON Response in Android/Java you need to do this:
Create a custom API Connector class
Declare a method that will return a JSON Array
Create a AsyncTask class (optional)
Decode JSONArray
1.
public class CustomAPIConnector {
public final String URL = "http://10.0.2.2/your-project-url/"; // 10.0.2.2 goes to computer localhost if you put localhost, it will go to the devices localhost which should not exist
2.
public JSONArray getUserInfo(String username, String password) {
HttpEntity httpEntity = null;
// Add your POST variables to receive on your backend
ArrayList<NameValuePair> nameValuePairs = new ArrayList<NameValuePair>();
nameValuePairs.add(new BasicNameValuePair("username",username));
nameValuePairs.add(new BasicNameValuePair("password",password));
try {
DefaultHttpClient httpClient = new DefaultHttpClient();
HttpPost httpPost = new HttpPost(URL + "login.php"); // have split up URL and page so you can redirect to different links easier if the URL changes
httpPost.setEntity(new UrlEncodedFormEntity(nameValuePairs));
HttpResponse httpResponse = httpClient.execute(httpPost);
httpEntity = httpResponse.getEntity();
} catch (IOException e) {
e.printStackTrace();
}
JSONArray jsonArray = null;
if(httpEntity != null) {
try {
String entityResponse = EntityUtils.toString(httpEntity);
jsonArray = new JSONArray(entityResponse);
} catch (JSONException e) {
e.printStackTrace();
} catch(IOException e) {
e.printStackTrace();
}
}
return jsonArray;
}
}
3.
private class AvailableUser extends AsyncTask<ApiConnector,Boolean,JSONArray> {
#Override
protected JSONArray doInBackground(ApiConnector... params) {
return params[0].availableUsername(etusername.getText().toString());
}
#Override
protected void onPostExecute(JSONArray jsonArray) {
checkAvailableUsername(jsonArray);
}
}
private class AvailableEmail extends AsyncTask<ApiConnector,Boolean,JSONArray> {
#Override
protected JSONArray doInBackground(ApiConnector... params) {
return params[0].availableEmail(etemail.getText().toString());
}
#Override
protected void onPostExecute(JSONArray jsonArray) {
checkAvailableEmail(jsonArray);
}
}
4.
private void checkAvailableEmail(JSONArray jsonArray) {
String s = "";
if(jsonArray != null) {
for (int i = 0; i < jsonArray.length(); i++) {
JSONObject json = null;
try {
json = new JSONObject();
json = jsonArray.getJSONObject(i);
if(!json.getString("count").isEmpty()) {
if(json.getString("count").equalsIgnoreCase("0")) {
status.setText("");
passedemail = true;
return;
} else {
status.setText("Email Taken");
passedemail = false;
return;
}
}
} catch (JSONException e) {
e.printStackTrace();
}
}
} else {
status.setText("Failed - checkAvailableEmail");
}
}
Please note that this is actual code I have in one of my apps that registersa user, the getUserInfo gets all information from the user, and the Available email asynctask class is separate from the getUserInfo, it is the registering part, that checks if the email is available.
From here on, you can copy the code and change what you need to.
JSON as name says java script object notation would help you to exploit OOPS , POST/GET and js at backend .
I use JSON , its easy to code , parse and handle
i wrote those threads:
How to manage multiple Async Tasks efficiently in Android
Running multiple AsyncTasks at the same time -- not possible?
but didnt find answer for my question, maybe someone can help..
I have android app which makes Login POST and getting json response,
if the Json is OK i need to POST another data to get another response.
i have extends Async Class which doing the post to the URL:
public class AsyncHttpPost extends AsyncTask<String, String, String> {
private HashMap<String, String> mData = null;
public AsyncHttpPost(HashMap<String, String> data) {
mData = data;
}
#Override
protected String doInBackground(String... params) {
byte[] result = null;
String str = "";
HttpClient client = new DefaultHttpClient();
HttpPost post = new HttpPost(params[0]);// in this case, params[0] is URL
try {
ArrayList<NameValuePair> nameValuePair = new ArrayList<NameValuePair>();
Iterator<String> it = mData.keySet().iterator();
while (it.hasNext()) {
String key = it.next();
nameValuePair.add(new BasicNameValuePair(key, mData.get(key)));
}
post.setEntity(new UrlEncodedFormEntity(nameValuePair, "UTF-8"));
HttpResponse response = client.execute(post);
StatusLine statusLine = response.getStatusLine();
if(statusLine.getStatusCode() == HttpURLConnection.HTTP_OK){
result = EntityUtils.toByteArray(response.getEntity());
str = new String(result, "UTF-8");
}
}
catch (UnsupportedEncodingException e) {
e.printStackTrace();
}
catch (Exception e) {
return null;
}
return str;
}
#Override
protected void onPostExecute(String result) {
try {
JSONArray Loginjson = new JSONArray(result);
strStt = Loginjson.getJSONObject(0).getJSONObject("fields").getString("status");
if (strStt.equals("ERR")) {
ErrorMsg("Authentication failed");
} else if (strStt.equals("OK")) {
ErrorMsg("Login OK!!!");
ClientPage();
} else {
ErrorMsg("Connection Error");
}
} catch (JSONException e) {
ErrorMsg("Connection Error");
}
}
}
Now - i need to get another POST if the status is Error. do i need to make another Async class? with the same all procedures ? the issue is only the onPostExecute part is different.. actually the "doInBackground" will be always the same..
any idea how can i easily do multiple posts in the same activity?
Firstly, since your doInBackground() code will always stay the same, I recommend you move it into a general utility class.
Beyond that, you can go one of two ways:
Create a new AsyncTask for each type of request that can call your utility class, and have its own onPostExecute()
Create one AsyncTask that has a flag in it, which can be checked in the onPostExecute() method to see what code needs to be executed there. You will have to pass the flag in in the constructor or as a parameter in execute.
You can use a parameter at AsyncHttpPost constructor/execute or global variable to indicate if it is first or second POST (by other words - a flag). Then just create and execute another instance of AsyncHttpPost in onPostExecute (only if parameter/variable is set as "first POST").
I am not reaching an onPostExecute in an AsyncTask Class.
I call the task this way, inside an onClick in a dialog box:
new HelpfulTask().execute(passing);
Note: When I hover over the above code, I get a warning:
A generic Array of ArrayList is created for a varargs
parameter.
I am not sure what that means and if that is preventing my Task from even running?
Here is the Task Code:
protected class UnHelpfulTask extends
AsyncTask<ArrayList<String>, Void, ArrayList<String>> {
ArrayList<String> passed;
protected ArrayList<String> doInBackground(ArrayList<String>... passing) {
passed = passing[0];
String url_select = "http://www.---.com/---/bad.php";
ArrayList<NameValuePair> param = new ArrayList<NameValuePair>();
param.add(new BasicNameValuePair("item", passed.get(0)));
param.add(new BasicNameValuePair("text", passed.get(1)));
param.add(new BasicNameValuePair("category", passed.get(2)));
HttpClient httpClient = new DefaultHttpClient();
HttpPost httpPost = new HttpPost(url_select);
try {
httpPost.setEntity(new UrlEncodedFormEntity(param));
HttpResponse httpResponse = httpClient.execute(httpPost);
HttpEntity httpEntity = httpResponse.getEntity();
// read content
is = httpEntity.getContent();
} catch (Exception e) {
Log.e("log_tag", "Error in http connection " + e.toString());
}
return null;
}
InputStream is = null;
String result = "";
protected void onPostExecute(Void v) {
Toast.makeText(getContext(), "You have voted this down!",
Toast.LENGTH_SHORT).show();
}
}
I get no errors on run and in the onPostExecute, the Toast never shows. (Note: This is an inner class inside of an ArrayAdapter.) I also added a toast to see if my ArrayList was unwrapping properly and put that in the onPostExecute but it never showed either.
How can I test to see if this Task is even running?
Change
protected void onPostExecute(Void v) {
so it is
protected void onPostExecute(ArrayList<String> arr)
Or change your AsyncTask declaration so it
extends AsyncTask<ArrayList<String>, Void, Void>
Which is the better idea since you return null in doInBackground(). The reason why you weren't getting the toast is because you were making a different method than what your AsyncTask specifies. This is why we ususally use the #Override annotation - it forces a check for actual overrides, which you need to do in classes like AsyncTasks.
Please can anyone tell me how to make an http post to work in the background with AsyncTask and how to pass the parameters to the AsyncTask? All the examples that I found were not clear enough for me and they were about downloading a file.
I'm running this code in my main activity and my problem is when the code sends the info to the server the app slows down as if it is frozen for 2 to 3 sec's then it continues to work fine until the next send. This http post sends four variables to the server (book, libadd, and time) the fourth is fixed (name)
Thanks in advance
public void SticketFunction(double book, double libadd, long time){
Log.v("log_tag", "%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% SticketFunction()");
//HttpClient
HttpClient nnSticket = new DefaultHttpClient();
//Response handler
ResponseHandler<String> res = new BasicResponseHandler();
HttpPost postMethod = new HttpPost("http://www.books-something.com");
try {
List<NameValuePair> nameValuePairs = new ArrayList<NameValuePair>(5);
nameValuePairs.add(new BasicNameValuePair("book", book+""));
nameValuePairs.add(new BasicNameValuePair("libAss", libass+""));
nameValuePairs.add(new BasicNameValuePair("Time", time+""));
nameValuePairs.add(new BasicNameValuePair("name", "jack"));
//Encode and set entity
postMethod.setEntity(new UrlEncodedFormEntity(nameValuePairs, HTTP.UTF_8));
//Execute
//manSticket.execute(postMethod);
String response =Sticket.execute(postMethod, res).replaceAll("<(.|\n)*?>","");
if (response.equals("Done")){
//Log.v("log_tag", "!!!!!!!!!!!!!!!!!! SticketFunction got a DONE!");
}
else Log.v("log_tag", "!!!!!!!?????????? SticketFunction Bad or no response: " + response);
} catch (ClientProtocolException e) {
// TODO Auto-generated catch block
//Log.v("log_tag", "???????????????????? SticketFunction Client Exception");
} catch (IOException e) {
// TODO Auto-generated catch block
//Log.v("log_tag", "???????????????????? IO Exception");
}
}
}
At first,
You put a class like following:
public class AsyncHttpPost extends AsyncTask<String, String, String> {
interface Listener {
void onResult(String result);
}
private Listener mListener;
private HashMap<String, String> mData = null;// post data
/**
* constructor
*/
public AsyncHttpPost(HashMap<String, String> data) {
mData = data;
}
public void setListener(Listener listener) {
mListener = listener;
}
/**
* background
*/
#Override
protected String doInBackground(String... params) {
byte[] result = null;
String str = "";
HttpClient client = new DefaultHttpClient();
HttpPost post = new HttpPost(params[0]);// in this case, params[0] is URL
try {
// set up post data
ArrayList<NameValuePair> nameValuePair = new ArrayList<NameValuePair>();
Iterator<String> it = mData.keySet().iterator();
while (it.hasNext()) {
String key = it.next();
nameValuePair.add(new BasicNameValuePair(key, mData.get(key)));
}
post.setEntity(new UrlEncodedFormEntity(nameValuePair, "UTF-8"));
HttpResponse response = client.execute(post);
StatusLine statusLine = response.getStatusLine();
if(statusLine.getStatusCode() == HttpURLConnection.HTTP_OK){
result = EntityUtils.toByteArray(response.getEntity());
str = new String(result, "UTF-8");
}
}
catch (UnsupportedEncodingException e) {
e.printStackTrace();
}
catch (Exception e) {
}
return str;
}
/**
* on getting result
*/
#Override
protected void onPostExecute(String result) {
// something...
if (mListener != null) {
mListener.onResult(result)
}
}
}
Now.
You just write some lines like following:
HashMap<String, String> data = new HashMap<String, String>();
data.put("key1", "value1");
data.put("key2", "value2");
AsyncHttpPost asyncHttpPost = new AsyncHttpPost(data);
asyncHttpPost.setListener(new AsyncHttpPost.Listener(){
#Override
public void onResult(String result) {
// do something, using return value from network
}
});
asyncHttpPost.execute("http://example.com");
First i would not recommend do a Http request in a AsyncTask, you better try a Service instead. Going back to the issue on how to pass parameter into an AsyncTask when you declared it you can defined each Object class of the AsyncTask like this.
public AsyncTask <Params,Progress,Result> {
}
so in your task you should go like this
public MyTask extends<String,Void,Void>{
public Void doInBackground(String... params){//those Params are String because it's declared like that
}
}
To use it, it's quite simple
new MyTask().execute("param1","param2","param3")