I've been trying to implement asynctask to make about 30 http requests to find the distance between two locations using a JSON object and the distance matrix api. The code I've written works when called from the main UI thread, but when I try to run it from the Async Task and save the distances to an array I just end up with an array full of null values. Any advice? (Note: This code was initially written by someone else at my work, and I've merely copy pasted it and changed a few lines to work with my app. So, there may be some unnecessary bits that I'm unaware of. Feel free to point them out)
class DistanceFinder extends AsyncTask<String[], Void, String[]>
{
#Override
protected String[] doInBackground(String[]... locations)
{
String baseURL="https://maps.googleapis.com/maps/api/distancematrix/json?origins=";
String[] distances = new String[locations[1].length];
for(int i = 1;i<locations.length;i++)
{
String url = baseURL + locations[0][0].replace(" ","+") + "&destinations=" + locations[1][i].replace(' ', '+') + "&sensor=true&units=imperial";
HttpClient httpclient = new DefaultHttpClient();
HttpResponse response;
String responseString = "";
boolean internet;
try
{
response = httpclient.execute(new HttpGet(url));
StatusLine statusLine = response.getStatusLine();
if(statusLine.getStatusCode() == HttpStatus.SC_OK)
{
ByteArrayOutputStream out = new ByteArrayOutputStream();
response.getEntity().writeTo(out);
out.close();
responseString = out.toString();
internet=true;
}
else
{
response.getEntity().getContent().close();
throw new IOException(statusLine.getReasonPhrase());
}
} catch (ClientProtocolException e)
{
// TODO Auto-generated catch block
e.printStackTrace();
internet=false;
Toast.makeText(getApplicationContext(), "Please connect to internet", Toast.LENGTH_LONG).show();
}
catch (IOException e)
{
// TODO Auto-generated catch block
e.printStackTrace();
internet=false;
Toast.makeText(getApplicationContext(),"Please connect to internet", Toast.LENGTH_LONG).show();
}
if(internet){
try
{
JSONObject jsonObj = new JSONObject(responseString);
JSONArray rows = jsonObj.getJSONArray("rows");
JSONObject inRows=rows.getJSONObject(0);
JSONArray elements = inRows.getJSONArray("elements");
JSONObject inElements=elements.getJSONObject(0);
JSONObject distance= inElements.getJSONObject("distance");
distances[i] = distance.getString("text");
}
catch (JSONException e)
{
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
return distances;
}
#Override
protected void onPostExecute(String[] result)
{
// TODO Auto-generated method stub
super.onPostExecute(result);
distancesList = result;
}
#Override
protected void onPreExecute()
{
// TODO Auto-generated method stub
super.onPreExecute();
}
}
Your problem is with you for loop
for(int i = 1;i<locations.length;i++)
First, you should start from 0, unless your first cell doesn't store a String you wish you check the distance to.
Second, your for loop should be
for(int i = 0;i<locations[0].length;i++)
Right now you're checking cells [1][0] and that's it, because the loop ends.
I tested it with manually entered locations and it works.
Also, just to make things easier for you to debug, You should really get used to using Log.d(). It really helps figuring out errors. I used it in your code and saw that the loop only gets executed once.
Good luck
P.s, as mentioned in one of the comments, remove the onPreExecute(). You don't use it.
Related
What is the native Android way to implement long running network operations (like uploading a bunch of photos) without having to use libraries like RoboSpice?
I've read numerous topics on stackoverflow suggesting that asynctask is not suitable for long running operations as it is closely tied to an activity's lifecycle, might lead to memory leaks and since android 3.2 there is only one thread for all asynctasks for an app. (not sure about this last one)
How do I replace my asynctask with something else?
Now, I've heard of handlers, executors, services and what not, but how exactly do I implement them in my code and which one to choose?
Here is an example of the asynctask I use
I have removed a lot of code, just so you can see the basic structure
public class UploadPhotosToServer extends AsyncTask<String, Void, Boolean> {
#Override
protected Boolean doInBackground(String... args) {
HashMap<String, String> params = new HashMap<String, String>();
try {
if(uploadImageToServer(id, path, params)) {
success = true;
} else {
success = false;
}
} catch (Exception e) {
e.printStackTrace();
success = false;
}
return success;
}
public boolean uploadImageToServer(int imageId, String imagePath, HashMap<String, String> params) throws Exception {
try {
JSONObject json = jsonParser.uploadImageToServer(imagePath, params);
JSONObject message = json.getJSONObject("message");
String serverResponse = message.getString("success");
if (serverResponse.contentEquals("true") {
return true;
} else {
return false;
}
} catch (JSONException e) {
e.printStackTrace();
return false;
} catch (Exception e) {
e.printStackTrace();
return false;
}
}
}
and here is jsonParser.uploadImageToServer
public JSONObject uploadImageToServer(String imagePath, HashMap<String, String> params) throws Exception {
HttpResponse response;
MultipartEntityBuilder multipartEntity;
HttpPost postRequest;
HttpContext localContext;
Bitmap bitmap;
try {
// Set the http handlers
httpClient = new DefaultHttpClient();
localContext = new BasicHttpContext();
postRequest = new HttpPost(SERVER + "images");
// Send the package
multipartEntity = MultipartEntityBuilder.create();
multipartEntity.setMode(HttpMultipartMode.BROWSER_COMPATIBLE);
multipartEntity.addPart("file", new FileBody(new File(imagePath)));
for (Map.Entry<String, String> entry : params.entrySet()) {
multipartEntity.addTextBody(entry.getKey(), entry.getValue());
}
postRequest.setEntity(multipartEntity.build());
// Get the response. we will deal with it in onPostExecute.
response = httpClient.execute(postRequest, localContext);
HttpEntity httpEntity = response.getEntity();
inputStream = httpEntity.getContent();
try {
BufferedReader reader = new BufferedReader(new InputStreamReader(inputStream, "iso-8859-1"), 8);
StringBuilder sb = new StringBuilder();
String line = null;
while ((line = reader.readLine()) != null) {
sb.append(line + "\n");
}
json = sb.toString();
inputStream.close();
reader.close();
} catch (ClientProtocolException e1) {
e1.printStackTrace();
} catch (IOException e1) {
e1.printStackTrace();
} catch (Exception e) {
e.printStackTrace();
}
// Try parsing the string to a JSON object
try {
jsonObject = new JSONObject(json);
} catch (JSONException e) {
e.printStackTrace();
}
// Return JSON String
return jsonObject;
} catch (Exception e) {
e.printStackTrace();
return null;
}
}
I think for a set of uploads I would consider implementing an IntentService. As explained at the link it will process a list of intents in a worker thread until that list is exhausted at which point the service will shutdown again.
The implementation of an IntentService is very simple. An example based on the example you give above;
public class ImageUploadIntentService extends IntentService {
public ImageUploadIntentService() {
super("ImageUploadIntentService");
}
#Override
public void onCreate() {
// Not a required implementation but you might want to setup any dependencies
// here that can be reused with each intent that the service is about to
// receive.
super.onCreate();
}
#Override
public void onHandleIntent(Intent intent) {
// Process your intent, this presumably will include data such as the local
// path of the image that you want to upload.
try {
uploadImageToServer(intent.getExtra("image_to_upload"), params);
} catch (Exception e) {
// Oh :( Consider updating any internal state here so we know the state
// of play for later
}
}
public JSONObject uploadImageToServer(String imagePath, HashMap<String, String> params) throws Exception {
// All of your upload code
}
}
Then to call the service it is as simple as;
Intent intent = new Intent(this, ImageUploadIntentService.class)
.putExtra("image_to_upload", mImagePath);
startService(intent);
This does leave us with the issue of indicating the progress of your upload queue. We can solve this by using a ResultReceiver. A result receiver is Parcelable so we can send it with the intent in order to listen out for results we might be interested in. You can handle the ResultReceiver with either an Activity and suitable piece of progress dialog, or if you want a persistent notification with a progress bar then you could use a Service to host the receiver.
It is a little more involved than using an AsyncTask, but it does give you a little more flexibility and is not as attached to the Activity lifecycle. Another gotcha with the IntentService it will still only make you one worker thread so image uploads could not happen concurrently. But I might consider breaking your Bitmap JPEG compression to it's own IntentService then you could have the compression happening on the next image in the queue while the first is being uploaded.
I have a method that need to update its status periodically to the server.
I am using AsyncTask to run the HTTP call in background.
PROBLEM: In onPostExecute method upon checking AsyncTask.getStatus, It show the previous task still running which is causing the error.
ERROR: java.lang.IllegalStateException: Cannot execute task: the task is already running.
DIFFERENT STRATEGIES USED TO SOLVE THE PROBLEM BUT NONE IS WORKING
1. Before Relaunching AsyncTask, checked the status, it is showing the thread is RUNNING.
2. Called the AsyncTask.cancel(true), immediately before calling the AsyncTask.execute if it is still running. It turns out AsyncTask still RUNNING and taking more than 3 mins to get cancel.
NOTE: I have checked many similar questions here, but haven't found helpful.
I would really appredicae if any one of you guys give me an example to solve this issue, Thanks a Million in advance......
public class MainActivity extends Activity implements AsyncResponse{
ConnectServer asyncTask =new ConnectServer();
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
asyncTask.delegate = this;
setContentView(R.layout.activity_main);
//Start updating server using below method
loop();
}
public void processFinish(String output){
//this you will received result fired from async class of onPostExecute(result) method.
//Log.v(TAG, output);
if(output != null){
//not using this at this point
}
}
//Method that will call Async method to reach server
public void loop(){
TextView b = (TextView) findViewById(R.id.mField);
String str;
try {
str = asyncTask.execute(true).get();
b.setText(str);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (ExecutionException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
// START SERVER CONNECTION
class ConnectServer extends AsyncTask<Boolean, String, String> {
public AsyncResponse delegate=null;
public int i = 0;
private Activity activity;
public void MyAsyncTask(Activity activity) {
this.activity = activity;
}
#Override
protected String doInBackground(Boolean... params) {
String result = null;
StringBuilder sb = new StringBuilder();
try {
// http post
HttpClient httpclient = new DefaultHttpClient();
HttpGet httppost = new HttpGet("http://192.168.0.21:8080");
HttpResponse response = httpclient.execute(httppost);
if (response.getStatusLine().getStatusCode() != 200) {
Log.d("GPSApp", "Server encountered an error");
}
BufferedReader reader = new BufferedReader(new InputStreamReader(response.getEntity().getContent(), "UTF8"));
sb = new StringBuilder();
sb.append(reader.readLine() + "\n");
String line = null;
while ((line = reader.readLine()) != null) {
sb.append(line + "\n");
}
result = sb.toString();
} catch (Exception e) {
Log.e("log_tag", "Error converting result " + e.toString());
}
return result;
}
#Override
protected void onPostExecute(String result) {
TextView mField = (TextView) findViewById(R.id.mField);
mField.setText(result+i);
try {
Thread.sleep(10000);
//asyncTask =new ConnectServer();
i++;
String str = asyncTask.execute(true).get();
mField.setText(str+i);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (ExecutionException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
protected void onPreExecute() {}
}
}
Call getStatus() to get the status of AsyncTask. If the status is AsyncTask.Status.RUNNING, cancel it.
I am new in android.I need to take values from web service.Here i used json parsing.The out put Json format is { "flag": 0 }. Here i need to take the value of flag and using that value i want to start another method. How do i take the value of flag. please help me. I used in this way.
public String objectvalue(String result){
try {
JSONObject obj=new JSONObject(result);
String flag=obj.getString("flag");
mString=flag;
System.out.println(mString);
} catch (JSONException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
return mString;
}
But i didnot get the value of flag.Here argument result is output from the server.ie,result={ "flag": 0 }
First of all, where is the declaration of mString variable? I assume it is declared as instance variable in your java class having this method, if not please check.
You have a well formed JSON in the form of
{ "flag": 0 }
so converting it to a JSONObject should work perfectly.
For extracting value of flag key
There is key named flag in this JSONObject which has an Integer value and you are trying to extract it using getString() method.
You should be using either of the following methods calls
optInt(String key)
Get an optional int value associated with a key, or zero if there is no such key or if th value is not a number. If the value is a string, an attempt will be made to evaluate it as a number.
int flag = optInt("flag");
OR
optInt(String key, int defaultValue)
Get an optional int value associated with a key, or the default if there is no such key or if the value is not a number. If the value is a string, an attempt will be made to evaluate it as a number.
int flag = optInt("flag", 0);
Your code with changes
public int objectValue(String result){
int flag = 0;
try {
JSONObject obj=new JSONObject(result);
flag = obj.optInt("flag");
} catch (JSONException e) {
e.printStackTrace();
}
return flag;
}
Edit: Answer to question in comment.
public String objectValue(String result){
int flag = 0;
try {
JSONObject obj=new JSONObject(result);
flag = obj.optInt("flag");
} catch (JSONException e) {
e.printStackTrace();
}
return String.valueOf(flag);
}
Hope this helps.
You may try using AsyncTask for your concern. It's best and preffered way to fetch JSON data
Define AsyncTask like this ..
new BussinessOwnerHttpAsyncTask().execute();
and your AsyncTask class ..
class BussinessOwnerHttpAsyncTask extends AsyncTask<String, Void, String> {
#Override
protected void onPreExecute() {
// TODO Auto-generated method stub
super.onPreExecute();
// Progress dialog code goes over here ..
pDialog = new ProgressDialog(getParent());
pDialog.setMessage("Please wait ...");
pDialog.setIndeterminate(false);
pDialog.setCancelable(false);
pDialog.show();
}
#Override
protected String doInBackground(String... params) {
// Maintaining Shared preferences class for further...
HttpClient httpclient = new DefaultHttpClient();
String myUrl = Your_url_goes_over_here;
String encodedURL = "";
try {
encodedURL = URLEncoder.encode(myUrl, "UTF-8");
} catch (UnsupportedEncodingException e1) {
// TODO Auto-generated catch block
e1.printStackTrace();
}
try {
URL url = new URL(encodedURL);
Log.d("asca", ""+url);
} catch (MalformedURLException e1) {
// TODO Auto-generated catch block
e1.printStackTrace();
}
Log.i("url", city_name + "~" + country_name);
Log.d("location", request_url+encodedURL);
HttpGet httpget = new HttpGet(request_url+encodedURL);
try {
httpresponse = httpclient.execute(httpget);
System.out.println("httpresponse" + httpresponse);
Log.i("response", "Response" + httpresponse);
InputStream is = httpresponse.getEntity().getContent();
InputStreamReader isr = new InputStreamReader(is);
BufferedReader br = new BufferedReader(isr);
StringBuilder sb = new StringBuilder();
String recievingDataFromServer = null;
while ((recievingDataFromServer = br.readLine()) != null) {
Log.i("CHECK WHILE", "CHECK WHILE");
sb.append(recievingDataFromServer);
}
myJsonString = sb.toString();
Log.d("manish", myJsonString);
serverSearchData = sb.toString();
} catch (ClientProtocolException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
return sb.toString();
}
#Override
protected void onPostExecute(String result) {
// TODO Auto-generated method stub
super.onPostExecute(result);
pDialog.dismiss();
if (myJsonString.length() > 0) {
try {
myJsonObject = new JSONObject(myJsonString);
String your_flag = myJsonObject.getString("flag");
} catch (Exception e) {
e.printStackTrace();
}
}
}
}
Now you are good to go with your queries..
{ // JSONObject
"flag": 0
}
Use
JSONObject obj=new JSONObject(result);
int flag=obj.getInt("flag");
http://developer.android.com/reference/org/json/JSONObject.html
public int getInt (String name)
Added in API level 1
Returns the value mapped by name if it exists and is an int or can be coerced to an int.
Throws
JSONException if the mapping doesn't exist or cannot be coerced to an int.
If this does not work you need to post more info.
the "flag" values format at interger, not string, this is simple code to do that :
int flagValues = jsonObject.getInt("flag");
Log.w("values ",String.valuesOf(flagValues));
I am trying to get an HttpResponse in xml but Im not getting the whole response, what is courious is that if I loop the request the response ends in different parts but is never full.
I use the same code to request things from different Urls but I only get problems with one.
Here is the code of the AsyncTask:
public class NetworkTask extends AsyncTask<String, Void, HttpResponse> {
private AsyncTaskListener listener;
#Override
protected HttpResponse doInBackground(String... params) {
String link = params[0];
HttpGet request = new HttpGet(link);
AndroidHttpClient client = AndroidHttpClient.newInstance("Android");
try {
HttpResponse httpResponse = client.execute(request).;
return httpResponse;
} catch (IOException e) {
e.printStackTrace();
return null;
} finally {
client.close();
}
}
#Override
protected void onPostExecute(HttpResponse result) {
if (result != null){
try {
String sRes = EntityUtils.toString(result.getEntity());
listener.onNTCompleted(sRes);
} catch (IllegalStateException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
public NetworkTask(AsyncTaskListener listener){
this.listener=listener;
}
}
I am not sure if this helps you but you have a problem because EntityUtils.toString() reads data from the network stream, which should not be done on UI thread (onPostExecute). Try moving EntityUtils.toString() to doInBackground() first. This may not help solve your problem, but it is the right thing to do.
I have a simple program that aks questions then call a php file saying if the answer was a yes or a no.
Right now it works but there is a slight pause when the information is being send. I would like some kind message or indicator to come up showing the computer is busy.
Now when I chnage the text of a textvue, before I send the data, the textView does not change, I allso tried to call it's update methed
code
case R.id.butYes:
mSend .setText("Sending your vote to server");
mSend.invalidate();
TalkToServer( mYes[mPes-1] );
UpdateScreen();
mSend .setText("");
break;
String TalkToServer( String addr)
{
HttpClient httpclient = new DefaultHttpClient();
HttpPost httppost = new HttpPost(addr);
HttpResponse response;
String responseBody=new String("");
try {
response = httpclient.execute(httppost);
responseBody = EntityUtils.toString(response.getEntity());
} catch (ParseException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
return responseBody;
}
use AsyncTask to avoid hanging of UI when sending data to server just change your code as:
case R.id.butYes:
new SendTextOperation().execute("");
break;
private class SendTextOperation extends AsyncTask<String, Void, String> {
#Override
protected void onPreExecute() {
//Update UI here
mSend.setText("Sending your vote to server");
mSend.invalidate();
}
#Override
protected String doInBackground(String... params) {
// Talk to server here to avoid Ui hanging
TalkToServer( mYes[mPes-1] );
return null;
}
#Override
protected void onPostExecute(String result) {
// Update screen here after talk to server end
UpdateScreen();
mSend .setText("");
}
}