AsyncTask executes Serial instead of Parallel (HTTPost TimeOutException) - java

EDIT: AsyncTask was called lots of times to update status in Server
and at the same time, my app tried to upload files. AsyncTask by
default, do only one operation at a time (serial mode) but you can put
it in Parallel mode, as I answered below.
After running normally during several hours (and sometimes a few minutes), my app stops connecting to the server with HTTPost. I set the Timeout to 20 sec and It's a good time since the connection is good (wifi). I have tested it in two servers: my own computer and a virtual private server. The problem happens equally.
Is there some way or reason for Android to avoid connecting to the http server?
Is there another reason for this to happen?
Is there a better way of doing this?
Thanks!!
This is how I make a POST request:
try{
new ConexaoHTTPPost.SolicitaDados(parametros).execute(url).get(20000, TimeUnit.MILLISECONDS);
} catch (InterruptedException e) {
new ReportException(getApplicationContext()).send(e,classeToErr);
} catch (ExecutionException e) {
new ReportException(getApplicationContext()).send(e,classeToErr);
} catch (TimeoutException e) {
new ReportException(getApplicationContext()).send(e,classeToErr);
}
HTTPost Code:
public class ConexaoHTTPPost {
public static String postDados(String urlUsuario, String parametrosUsuario) {
URL url;
HttpURLConnection connection = null;
try {
url = new URL(urlUsuario);
connection = (HttpURLConnection) url.openConnection();
connection.setRequestMethod("POST");
connection.setRequestProperty("Content-Type", "application/x-www-form-urlencoded");
connection.setRequestProperty("Content-Lenght","" + Integer.toString(parametrosUsuario.getBytes().length));
connection.setRequestProperty("Content-Language","pt-BR");
connection.setUseCaches(false);
connection.setDoInput(true);
connection.setDoOutput(true);
OutputStreamWriter outputStreamWriter = new OutputStreamWriter(connection.getOutputStream(), "UTF-8");
outputStreamWriter.write(parametrosUsuario);
outputStreamWriter.flush();
outputStreamWriter.close();
InputStream inputStream = connection.getInputStream();
BufferedReader bufferedReader = new BufferedReader(new InputStreamReader(inputStream, "UTF-8"));
StringBuffer resposta = new StringBuffer();
String linha;
while ( (linha = bufferedReader.readLine()) != null){
resposta.append(linha);
resposta.append('\r');
}
bufferedReader.close();
return resposta.toString();
}catch (Exception erro){
return null;
}finally {
if(connection != null){
connection.disconnect();
}
}
}
public static class SolicitaDados extends AsyncTask<String, Void, String> {
private String parametros;
//private String resultado = null;
public SolicitaDados(String parametros) {
this.parametros = parametros;
}
#Override
protected String doInBackground(String... urls) {
return ConexaoHTTPPost.postDados(urls[0], parametros);
}
/*
#Override
protected void onPostExecute(String resultado){
this.resultado = resultado;
}
*/
}
}

I solved It.
I was using execute() method but, actually, the correct way is to use executeOnExecutor() in this line:
new ConexaoHTTPPost.SolicitaDados(parametros).execute(url).get(20000,
TimeUnit.MILLISECONDS);
execute() executes everything in serial in the UI Thread, so you can't upload two files (or data) at the same time because the connection get blocked by the UI thread.
When using executeOnExecutor() method, you can upload multiple files ou data. I had only to change this line as shown:
new ConexaoHTTPPost.SolicitaDados(parametros).executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR,
url).get(20000, TimeUnit.MILLISECONDS);
I changed it in all places it appears.
PS: You have to use AsyncTask.THREAD_POOL_EXECUTOR as a Thread Executor.

Related

How to make http call from standalone java application

I'm making a small dictionary kind of app using java swings. I'm using oxford dictionary api for that. Is there any way to make a simple ajax request in java without using servelets and all advanced java concepts. As in android we use http url connection to do this job.I googled a lot for finding this but I could't find a solution as every page is showing results using servelets. But I know core java alone.If it is possible to make ajax call without servelts please help me...Thanks in advance...
Use HttpURLConnection class to make http call.
If you need more help for that then go for offical documentation site of java Here
Example
public class JavaHttpUrlConnectionReader {
public static void main(String[] args) throws IOException{
String results = doHttpUrlConnectionAction("https://your.url.com/", "GET");
System.out.println(results);
}
public static String doHttpUrlConnectionAction(String desiredUrl, String requestType) throws IOException {
BufferedReader reader = null;
StringBuilder stringBuilder;
try {
HttpURLConnection connection = (HttpURLConnection) new URL(desiredUrl).openConnection();
connection.setRequestMethod(requestType);// Can be "GET","POST","DELETE",etc
connection.setReadTimeout(3 * 1000);
connection.connect();// Make call
reader = new BufferedReader(new InputStreamReader(connection.getInputStream()));// Reading Responce
stringBuilder = new StringBuilder();
String line;
while ((line = reader.readLine()) != null) {
stringBuilder.append(line).append("\n");
}
return stringBuilder.toString();
} catch (IOException e) {
throw new IOException("Problam in connection : ", e);
} finally {
if (reader != null) {
try {
reader.close();
} catch (IOException ioe) {
throw new IOException("Problam in closing reader : ", ioe);
}
}
}
}
}
It will make a call and give response as return string. If you want to make POST call the need to do some extra for that :
try{
DataOutputStream wr = new DataOutputStream(connection.getOutputStream());
wr.write(postParam.getBytes());
} catch(IOException e){
}
Note : Here postParam is String type with value somthing like "someId=156422&someAnotherId=32651"
And put this porson befor connection.connect() statement.

Calling methods after new Class.execute() crash, android studio

Basically, i have an app that uses JSON. I get the JSON in new HentData.execute(); and pass it to a string variable. But when I try to acutally do something with it my program crashes.
HentData extends AsyncTask, I know it gives me a JSON string that works
INSIDE oncreate()
new HentData().execute();
jsonToArray();
arrayToText();
This crashes
But when I run them like this it works, do I have to close the HentData class somehow?
protected void onPostExecute(String resultat){
json_string = resultat;
jsonToArray();
arrayToText();
}
This is my doInBackground()
protected String doInBackground(Void... voids){
try {
URL url = new URL(json_url);
HttpURLConnection httpURLConnection = (HttpURLConnection) url.openConnection();
InputStream IS = httpURLConnection.getInputStream();
BufferedReader bufferedReader = new BufferedReader(new InputStreamReader(IS));
StringBuilder sb = new StringBuilder();
while((json_string = bufferedReader.readLine())!=null){
sb.append(json_string+"\n");
}
bufferedReader.close();
IS.close();
httpURLConnection.disconnect();
return sb.toString().trim();
} catch (MalformedURLException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
return null;
}
But when I run them like this it works, do I have to close the HentData class somehow?
protected void onPostExecute(String resultat){
json_string = resultat;
jsonToArray();
arrayToText();
}
You don't have to close anything. This works because "async" in AsyncTask makes the code run in the background.
In other words,
new HentData().execute(); // Not waiting for result
jsonToArray(); // Continue on, even though there is no result yet --> error
arrayToText();
If you want a more flexible way to get results, see How to get the result of OnPostExecute() to main activity because AsyncTask is a separate class?
If you hate writing AsyncTasks (for HTTP methods), see Comparison of Android networking libraries: OkHTTP, Retrofit, and Volley

Wrong Mime-Type when downloading binary file on mobile data (Android)

I'm trying to download a binary file using:
URL url = new URL(urlStr);
HttpURLConnection ucon = (HttpURLConnection) url.openConnection();
ucon.connect();
InputStream is = new BufferedInputStream(ucon.getInputStream());
When run via mobile data (on Samsung Galaxy 4, Android 5.0.1) I receive the following response
j���UFEHLER��6ERROR��`Заявеното съдържание не може да бъде заредено ��&Wrong MIME-Type���Fback��2
Which means "The content requested cannot be loaded" in Bulgarian (the server I download from is Bulgaria). But more informative seems "Wrong MIME-Type" at the end of the response.
I tried the same using HttpGet with no result.
The weird thing is everything is ok when I execute the same request via Wifi.
Also I can download the file from the brower on mobile data, but not for the code. Also I've tested on Lenovo with Android 4.4.2 via mobile data and is also worked.
I noticed I'm getting Content-Type: application/vnd.wap.wmlc (logged ucon.getResponseCode()) when connected via mobile data and nothing set as content type when via WiFi.
Any ideas? :/
Here's my working code for file downloading. You can have a look to check if you're missing something.
public class ImageDownloaderAsyncTask extends
AsyncTask<Void, Integer, Integer> {
private static File f;
protected void doInBackground() throws IOException {
File dir = new File(Constants.FILE_PATH);
if (!dir.exists()) dir.mkdir();
f = new File(Constants.FILE_PATH + Constants.FILE_NAME);
if (f != null && !f.exists()) {
f.createNewFile();
}
try {
URL url = new URL(fileUrl);
HttpURLConnection connection = (HttpURLConnection) url.openConnection();
connection.setDoInput(true);
connection.connect();
InputStream input = connection.getInputStream();
String data1 = f.getPath();
FileOutputStream stream = new FileOutputStream(data1);
byte data[] = new byte[4096];
int count;
while ((count = input.read(data)) != -1) {
// allow canceling with back button
if (isCancelled()) {
input.close();
}
stream.write(data, 0, count);
}
stream.close();
} catch (Exception e) {
e.printStackTrace();
}
}
#Override
protected Integer doInBackground(Void... params) {
try {
doInBackground();
} catch (IOException e) {
e.printStackTrace();
}
return 1;
}
protected void onPostExecute(Integer result) {}
}

BufferedReader.readLine() blocks for a while

I am trying to get a String of http response (just a JSON object), and sometimes this piece of code waits infinite time in
line = reader.readLine()
May be, the reason of such behavior is bad Internet connection (I use 3G modem), but I need a stable solution to avoid this infinite lock. What can be done here to avoid it?
HttpResponse response = httpClient.execute(httpPost);
InputStream content = null;
JSONObject json_obj;
if (response.getStatusLine().getStatusCode() == 200) {
HttpEntity entity = response.getEntity();
try {
content = entity.getContent();
BufferedReader reader = new BufferedReader(new InputStreamReader(content, "UTF-8"), 256);
StringBuilder sb = new StringBuilder();
String line;
while ((line = reader.readLine()) != null) {
sb.append(line);
}
} catch (Exception e) {}
}
You can specify a read timeout:
HttpClient client = new DefaultHttpClient();
client.getParams().setParameter(CoreConnectionPNames.SO_TIMEOUT, 30000);
Should set a read timeout to 30 seconds.
Probably, you also want to specify a connection timeout:
client.getParams().setParameter(CoreConnectionPNames.CONNECTION_TIMEOUT, 30000);
readLine()
Or any network/IO should be done in a background thread to prevent locking of the main thread.
If you test your code on Android 4.0+ you'll also see that networking is no longer allowed on the main thread and will throw an exception.
Take a look at AsyncTask which is a simple, painless way of running such tasks on a background thread.
A good solution to avoid the "infinite" lock is to do this http calls in a separate thread, and with a Handler, notice to the main thread that the info is loaded and can use it like you want.
Here an example of my own using a SaxParser too:
public void SearchFromSuperClass(String text)
{
mHandler = new Handler();
Thread t = new Thread(){
public void run() {
try {
String strurl="URLTOPATH";
URL url = new URL(strurl);
SAXParserFactory factory = SAXParserFactory.newInstance();
SAXParser parser = factory.newSAXParser();
FundsHandlerRanking handler = new FundsHandlerRanking();
parser.parse(url.openConnection().getInputStream(), handler);
search_response = handler.getrankings();
mHandler.post(mUpdateResults);
} catch (Exception e) {
search_response = null;
mHandler.post(mUpdateResults);
}
}
};
t.start();
}
final Runnable mUpdateResults = new Runnable() {
public void run() {
updateResultsInUi();
}
};
private void updateResultsInUi() {
try
{
if(search_response != null)
{
lview.setAdapter(new SearchRankingAdapter(mycontext, search_response, false));
}
Pdialog.dismiss();
}
catch (Exception e) {
lview.setAdapter(null);
if (Pdialog.isShowing())
{
Pdialog.dismiss();
}
}
}
With mHandler.post(...) you put the call in the queue to be sended to the main UI thread, and there, you can modify UI objects without problem (CAN'T modify UI objects outside the Main thread).
Hope this helps

How to handle problem with Network Connectivity in Java

I have a simple java code which gets html text from the input url:
try {
URL url = new URL("www.abc.com");
// Get the response
BufferedReader rd = new BufferedReader(new InputStreamReader(url.openStream()));
while ((line = rd.readLine()) != null) {
String code = code + line;
} catch (IOException e){}
I am using this code in an android project. Now the problem comes when there is no internet connectivity. The application just halts and later gives error.
Is there some way to break this after some fixed timeout, or even return some specific string after an exception is thrown. Can you please tell me how to do that??
Try this:
try
{
URL url = new URL("www.abc.com");
String newline = System.getProperty("line.separator");
InputStream is = url.openStream();
if (is != null)
{
BufferedReader rd = new BufferedReader(new InputStreamReader(is));
StringBuilder contents = new StringBuilder();
while ((line = rd.readLine()) != null)
{
contents.append(line).append(newline);
}
}
else
{
System.out.println("input stream was null");
}
}
catch (Exception e)
{
e.printStackTrace();
}
An empty catch block is asking for trouble.
I don't know what the default timeout is for URL, and a quick look at the javadocs doesn't seem to reveal anything. So try using HttpURLConnection directly instead http://download.oracle.com/javase/1.5.0/docs/api/java/net/HttpURLConnection.html. This lets you set timeout values:
public static void main(String[] args) throws Exception {
URL url = new URL("http://www.google.com");
HttpURLConnection conn = (HttpURLConnection) url.openConnection();
conn.setConnectTimeout(5000); // 5 seconds
conn.setRequestMethod("GET");
conn.connect();
BufferedReader rd = new BufferedReader(new InputStreamReader(conn.getInputStream()));
String line;
while ((line = rd.readLine()) != null) {
System.out.println(line);
}
conn.disconnect();
}
You can also set a read time out as well, as well as specify behaviour re redirects and a few other things.
I think in addition to timeouts it could be also smart to check the Internet availability right before the requesting:
public class ConnectivityHelper {
public static boolean isAnyNetworkConnected(Context context) {
return isWiFiNetworkConnected(context) || isMobileNetworkConnected(context);
}
public static boolean isWiFiNetworkConnected(Context context) {
return getWiFiNetworkInfo(context).isConnected();
}
public static boolean isMobileNetworkConnected(Context context) {
return getMobileNetworkInfo(context).isConnected();
}
private static ConnectivityManager getConnectivityManager(Context context) {
return (ConnectivityManager) context.getSystemService(Context.CONNECTIVITY_SERVICE);
}
}
UPDATE: For timeouts see an excellent kuester2000's reply here.
Just a general tip on working with Streams always close them when they are no longer needed. I just wanted to post that up as it seems that most people didn't take care of it in their examples.

Categories

Resources