Android: making 2 consecutive http requests - android

I'm getting an address from the user and i'm using GeoCoder to get the lat/lng.
After getting the lat/lng I need to send a POST request to my server to save the data (using Volley).
I'm running the GeoCoder request in an AsyncTask and I run the post request in the onPostExecute callback.
Is that the right way to do it or is there a better way?
here is my code:
private class GeoCoderAsync extends AsyncTask<String, Void, List<Address>>{
#Override
protected List<Address> doInBackground(String... params) {
String address = params[0];
List<Address> addresses = null;
Geocoder coder = new Geocoder(Favorites.this);
try {
addresses = coder.getFromLocationName(address, 1);
} catch (IOException e) {
e.printStackTrace();
}
return addresses;
}
#Override
protected void onPostExecute(List<Address> result) {
Utils.dismissDialog(progDialog);
if (result != null) {
Address address = result.get(0);
...
//this makes a post request
VolleyHelper.post(request,AppConstants.URL.FAVORITES, getFavoritesSuccess(), getFavoritesError(), progDialog);
} catch (JSONException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
else{
Log.d(TAG, "Got Nothing!!!");
}
}
}

I'm pretty sure that your way is the best. As you commented, you need to wait until onPost to use volley so there is no way around it. Anyways, volley uses its own multi threading and so it won't lock anything up.
In general it is best to minimize http requests due to the battery cost from the radio, but in this case it is key to the functionality of your app so there is no way around it.
Btw, for anyone reading this question and curious about volley -http://arnab.ch/blog/2013/08/asynchronous-http-requests-in-android-using-volley/
Hope this helps ;)

I'm running the GeoCoder request in an AsyncTask and I run the post
request in the onPostExecute callback.
Is that the right way to do it
No, because onPostExecute run on main ui Thread. if you do this then UI will freeze until Http post request not completed.
or is there a better way?
Make post request from doInBackground after getting addresses from Geocoder.

Related

can I put network process and database process together under the same method in AsyncTask

see the code below, I put network request and local database write operation together under the same method.
ConcurrentAsyncTask.execute(new Runnable() {
#Override
public void run() {
Pair<String, String> rlt = null;
try {
rlt = sc.createNewDir(repoID, parentDir, dirName);
} catch (SeafException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
String newDirID = rlt.first;
String response = rlt.second;
// The response is the dirents of the parentDir after creating
// the new dir. We save it to avoid request it again
mDatabaseHelper.saveDirents(repoID, parentDir, newDirID, response);
}
});
sc.createNewDir() was used to request network request and mDatabaseHelper.saveDirents() was used to write data into database.
I wonder if it breaks the programming rules of AsyncTask.
Waiting for your advice, thanks!
There is nothing wrong with running different background operations in a single AsyncTask, especially when these operations are logically connected - as in your case network operation produces input for database operations, also you always want to store network operation result to database.

Different results between Android Geocoder and Google Geocoding web service

I am creating an Android application and I need to use the geolocation.
I have started by using the Geocoder API from Android (android.location.geocoder) but it causes some issues (timed out waiting for response from server) which seems to be common according to what I have read.
To make my application work when this kind of error occurs, I use the Geocoding web service.
Now, the application works every time. The problem is that the results returned by the geocoder from API and the geocoder from the web service are not the same.
For example the web service returns only 3 addresses with only city name and country whereas the geocoding from the API returns about 8 addresses with the feature name, the thoroughfare, the locality...
The question is: is there a way to make the results from the web service exactly the same than the ones from the API?
EDIT
Here is my MainGeocoder class:
public class MainGeocoder {
private Geocoder geocoderAPI;
private GeocoderRest geocoderRest;
public MainGeocoder(Context context) {
geocoderAPI = new Geocoder(context);
geocoderRest = new GeocoderRest(context);
}
public List<Address> getFromLocationName(String search, int maxResults) {
List<Address> addresses;
try {
addresses = geocoderAPI.getFromLocationName(search, maxResults);
return addresses;
} catch (IOException e) {
e.printStackTrace();
try {
addresses = geocoderRest.getFromLocationName(search, maxResults);
return addresses;
} catch (IOException e1) {
return null;
} catch (LimitExceededException e1) {
return null;
}
}
}
}
It basically tries to get the list of addresses from the API Geocoder. If an IO exception is thrown it gets this list from the web service by using the GeocoderRest class which has been pasted from here: https://stackoverflow.com/a/15117087/3571822
Is there a way to make the results from the web service exactly the
same than the ones from the API?
Simply no. In the majority of attempts there will always be a difference between these two geocoders. Because the android.location.Geocoder uses a Service internally, which you can't track down in the source code, you will never now where exactly the difference is, but asking Google. And I don't think they will give this info away.
Btw, the GeocoderRest class you use doesn't parse even the half of the info contained in the response. Usually the web service is much more reliable as the API in the SDK.

AsyncTask hangs on at beginning

AsyncTask works fine in Android 4.x, but not for Android 2.3.6. I've step-by-step debugged Android 2.3.6 with a physical mobile device.
It hangs on here:
myTask = new GetDataFromServer();
GetDataFromServer is the class of AsyncTask.
What's going on?
Here under is my code, I only used 1 AsyncTask in my code and received messages from server.
that's all.
class GetDataFromServer extends AsyncTask<String, String, String>
{
protected void onPreExecute ()
{
progressDialog1=ProgressDialog.show(MainActivity.this, "Loading data", "Please wait...",true);
}
protected String doInBackground(String... params)
{
String resulttxt="";
try {
serverIp = InetAddress.getByName("192.168.1.123");
int serverPort=31000;
Socket clientSocket=new Socket(serverIp,serverPort);
BufferedWriter bw=new BufferedWriter(new OutputStreamWriter(clientSocket.getOutputStream()));
bw.write(params[0]);
bw.flush();
BufferedReader br=new BufferedReader(new InputStreamReader(clientSocket.getInputStream()));
resulttxt=br.readLine();
if(resulttxt.contains("OK"))
{
publishProgress(resulttxt);
}
else
{
publishProgress(resulttxt);
clientSocket.close();
bw.close();
br.close();
return null;
}
resulttxt="";
resulttxt=br.readLine();
resulttxt=resulttxt.trim();
clientSocket.close();
} catch (IOException e) {
if(Status_txt!=null)
Status_txt.append( "Server is done.");
}
catch (NetworkOnMainThreadException e){
if(Status_txt!=null)
Status_txt.append( "NetworkOnMainThreadException");
}
return resulttxt;
}
protected void onProgressUpdate(String...inStr){
String[] strData=inStr[0].split("_");
String szTemp="Last Purchase Date: ";
szTemp+=strData[1];
szTemp+=" ,Valid days: ";
szTemp+=strData[2];
//Status_txt.setText(szTemp);
if(Status_txt!=null)
Status_txt.setText("You Are The Super User");
}
protected void onPostExecute(String data) {
tl_prediction2.removeAllViews();
if (data == null)
{
}
else {
if((data.contains("#")==true) || (data.contains("*")==true)
||data.contains("&")==true)
{
String[] arrayTmp=data.split("#");
for(Integer i=0;i<arrayTmp.length;i++)
{
String[] SubArrayTmp=arrayTmp[i].split("_");
tl_prediction2.addView(generateRow(4,SubArrayTmp));
}
}
}
progressDialog1.dismiss();
}
};
Since you haven't posted any code, I could only give you some random probable solutions:
May be your AsyncTask is taking a lot of time to download. Trying increasing its priority using android.os.Process.setThreadPriority(9) inside doInBackground()
Check if you have other previous running long AsyncTask in your code. AsyncTask by default operates on a single background thread. That means your AsyncTask task wouldn't be executed unless your previous AsyncTask are done. To allow parallel execution use executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR, params). You can read more here
Check for Internet and other permissions in Manifest. This is mostly where people make mistake.
AsyncTask works with ThreadPool. If there too many synctasks are executing, the later AsyncTask will be blocked by others. I think you can use the thread tool in DDMS to check the How many ayncTasks are executing.

Android app doesn't work on Android 4

I created an Android project on 2.3.3 and tried it on mobile 2.3.3, everything works OK. It didn't work on mobile 4, so I re-built for Android 4, but I have the same problem.
This is the code:
public void FTP_Download(){
String server = "192.168.1.135";
int port = 21;
String user = "pc1";
String pass = "1551";
FTPClient ftpClient = new FTPClient();
try {
ftpClient.connect(server, port);
ftpClient.login(user, pass);
ftpClient.enterLocalPassiveMode();
ftpClient.setFileType(FTP.BINARY_FILE_TYPE);
Toast.makeText(getBaseContext(), "download starting.",Toast.LENGTH_LONG).show();
// APPROACH #1: using retrieveFile(String, OutputStream)
String remoteFile1 = "i.xml";
File downloadFile1 = new File("sdcard/i.xml");
OutputStream outputStream1 = new BufferedOutputStream(new FileOutputStream(downloadFile1));
boolean success = ftpClient.retrieveFile(remoteFile1, outputStream1);
outputStream1.close();
if (success) {
Toast.makeText(getBaseContext(), "File #1 has been downloaded successfully.",Toast.LENGTH_LONG).show();
}
} catch (IOException ex) {
System.out.println("Error: " + ex.getMessage());
ex.printStackTrace();
} finally {
try {
if (ftpClient.isConnected()) {
ftpClient.logout();
ftpClient.disconnect();
}
} catch (IOException ex) {
ex.printStackTrace();
}
}
}
Note:
I use commons-net-3.1 to connect.
In android version 2.3 above you can not start internet connection from main UI thread. Instead you should use AsyncTask. I assumed you are not using AsyncTask. If you are, then post the code and log cat also. Some examples of other operations that ICS and HoneyComb won't allow you to perform on the UI thread are:( from link posted in comment below ) -
Opening a Socket connection (i.e. new Socket()).
HTTP requests (i.e. HTTPClient and HTTPUrlConnection).
Attempting to connect to a remote MySQL database.
Downloading a file (i.e. Downloader.downloadFile()).
You should not use the main UI Thread to start a network connection or read/write data from it as #phazorRise explained it. But I strongly disagree with using an AsyncTask to perform your download. AsyncTask have been designed for short living operations and downloading a file doesn't belong to that category.
The most relevant way to achieve your goal, if your files are big (and I assume it depends on users, so we can say they are big) is to use a service to download the files.
I invite you to have a look at RoboSpice, it will give your app robustness for networking and it's really the most interesting library for network requests on Android.
Here is an inforgraphics to get familiarized with alternatives and understand why using a service is better than any other technology.
When I use "internet conections" programming for andoid 4, I do an Async Task as follows:
You can put this Class code into the same file as principal file to intercatue with global variables or functions.
public class MyAsyncTask extends AsyncTask<String, Void, String> {
#Override
protected String doInBackground(String... urls) {
String url = urls[0]
try {
//Connection request code, in your case ftp
} catch (Exception e) {
//Catch code
}
}
#Override
protected void onPostExecute(String result) {
//Code to de After the connection is done
}
}
Then, in the Activity I call the Asyn Task
String url = "http://...";
new MyAsyncTask().execute(url);
Edit
Here it's explained how to use Async Task, with an example
http://developer.android.com/reference/android/os/AsyncTask.html
I added this code, and all thing OK
StrictMode.ThreadPolicy policy = new StrictMode.ThreadPolicy.Builder().permitAll().build();
StrictMode.setThreadPolicy(policy);
Note: I taked the code from #user1169115 comment in another post.
This isn't the best soluation, but I don't know why asynctask isn't work, so I don't have another choice.

Screen Halt while Communication(Client/Server) in Android

I have an application in which there is Google map, location overlays on Google map and a separate thread which send the current location of device to server after every 30 seconds. The problem is that when the thread sends the location to server the screen of device halted until the server respond. Here is the following code,
Global Object
private Handler handlerTimer = new Handler();
In onCreate Method
handlerTimer.removeCallbacks(taskUpdateStuffOnDialog );
handlerTimer.postDelayed(taskUpdateStuffOnDialog , 100);
And here is the taskUpdateStuffOnDialog
private Runnable taskUpdateStuffOnDialog = new Runnable()
{
public void run()
{
try
{
URL url3 = new URL("http://"+ appState.getURL()+"//iLocator/IDForClient.php?reg_no="+ Device_ID[0]);
HttpURLConnection conn = (HttpURLConnection) url3.openConnection();
BufferedReader reader = new BufferedReader(new InputStreamReader(conn.getInputStream()));
String quote = reader.readLine();
while (quote != null)
{
Device_ID = quote.split("\n");
quote = reader.readLine();
bCheckID = true;
}//End While
positionOverlay.setID(Device_ID[0]);
addEvent(Device_ID[0]);
}//End try
catch (Exception e)
{
e.printStackTrace();
Toast.makeText(MainMapActivity.this, "Communication Issue",Toast.LENGTH_LONG).show();
}//End catch
handlerTimer.postDelayed(this, 9000);
}
};
Please tell me what is wrong with my code.
The problem is that, although you're spawning a new Thread, you aren't spawning a new process. Everything you're doing is still in the user interface process, and that's blocking. You can find more information on the topic on developer.android.com.
The quickest and easiest way to get around this is using the IntentService class. It will only allow one HTTP request to be executed at a time, but will take care of all the problems for you.
Try using the AsyncTask for connecting to the Server. See an example here: http://developer.android.com/reference/android/os/AsyncTask.html

Categories

Resources