Confused too much! What is the sole purpose of using BufferReader, InputStream and StringBuffer. Why they should be used and in what kind of a sequence / pattern we should code them. I recently came across a chunk of code while understanding how to send and receive HTTP requests using HttpUrlConnection in android. I tried to search for all these terms and I did not get what I need. In this case, how to use each of them in a sequence or pattern? Any simple example for using all these three in combination would be great. And also kindly what should be all these 3 in layman terms? Thanks
InputStream is used for reading byte based data from the web server (or url) one byte at a time.
BufferReader it is used for reading data from an input stream all by once
StringBuffer A modifiable sequence of characters for use in creating strings, where all accesses are synchronized. This class has mostly been replaced by StringBuilder because this synchronization is rarely useful. This class is mainly used to interact with legacy APIs that expose it. [Did not understand what it means as my official language is not English]
//These two need to be declared outside the try/catch
//so that they can be closed in the finally block.
HttpURLConnection urlConnection = null;
BufferedReader reader = null;
//Will contain the raw JSON response as a string.
String forecastJsonStr = null;
try {
//Construct the URL for the OpenWeatherMap query
//Possible parameters are avaiable at OWM's forecast API page, at
//http://openweathermap.org/API#forecast
URL url = new URL("http://api.openweathermap.org/data/2.5/forecast/daily?q=94043&mode=json&units=metric&cnt=7");
//Create the request to OpenWeatherMap, and open the connection
urlConnection = (HttpURLConnection) url.openConnection();
urlConnection.setRequestMethod("GET");
urlConnection.connect();
//Read the input stream into a String
InputStream inputStream = urlConnection.getInputStream();
StringBuffer buffer = new StringBuffer();
if (inputStream == null) {
//Nothing to do.
forecastJsonStr = null;
}
reader = new BufferedReader(new InputStreamReader(inputStream));
String line;
while ((line = reader.readLine()) != null) {
//Since it's JSON, adding a newline isn't necessary (it won't affect parsing)
//But it does make debugging a *lot* easier if you print out the completed
//buffer for debugging.
buffer.append(line + "\n");
}
if (buffer.length() == 0) {
//Stream was empty. No point in parsing.
forecastJsonStr = null;
}
forecastJsonStr = buffer.toString();
} catch (IOException e) {
Log.e("PlaceholderFragment", "Error ", e);
//If the code didn't successfully get the weather data, there's no point in attemping
//to parse it.
forecastJsonStr = null;
} finally{
if (urlConnection != null) {
urlConnection.disconnect();
}
if (reader != null) {
try {
reader.close();
} catch (final IOException e) {
Log.e("PlaceholderFragment", "Error closing stream", e);
}
}
}
Related
I'm following an example of using the Reddit API in an Android app. I'm using Android Studio and Java. I have a link which returns a JSON object on a GET request (let's say http://www.reddit.com/r/dragonforce/.json), and the tutorial has this piece of code:
public static HttpURLConnection getConnection(String url){
System.out.println("URL: "+url);
HttpURLConnection hcon = null;
try {
hcon=(HttpURLConnection) new URL(url).openConnection();
hcon.setReadTimeout(30000); // Timeout at 30 seconds
hcon.setRequestProperty("User-Agent", "Alien V1.0");
} catch (MalformedURLException e) {
Log.e("getConnection()",
"Invalid URL: "+e.toString());
} catch (IOException e) {
Log.e("getConnection()",
"Could not connect: "+e.toString());
}
return hcon;
}
and
public static String readContents(String url){
HttpURLConnection hcon=getConnection(url);
if(hcon==null) return null;
try{
StringBuffer sb=new StringBuffer(8192);
String tmp="";
BufferedReader br=new BufferedReader(
new InputStreamReader(
hcon.getInputStream()
)
);
tmp = br.readLine();
while(tmp !=null) {
sb.append(tmp).append("\n");
tmp = br.readLine();
}
br.close();
return sb.toString();
}catch(IOException e){
Log.d("READ FAILED", e.toString());
return null;
}
}
I separated the tmp assignment for debug purposes. The problem is that nothing is read from the inputStream, and it returns an empty buffer to the JSONObject parser, resulting in JSONException end of input at character 0 of. I have user-permission in the Manifest for INTERNET, and the syntax for reading from the URL seems to be backed up by other sources on the internet, but it still seems something is amiss. Any help would be appreciated.
For anyone who is reading this down the line, the problem was that the URL in the tutorial was using HTTP instead of HTTPS, leading to a redirect response code and wasn't returning anything.
I have used map in my android application. I passed origin and destination latlon and get data from map url then parse the response.
But while auditing below code as marked for DOS attack stating that "This code might allow an attacker to crash the program or otherwise make it unavailable to legitimate users."
Concern : What if attacker push too large file then it will go on line by line and loop will be run for too long.
Proposed solution : Do not allow to read more than specific file size, so that it won't read file beyond some limit
Here is my code :
String url = "https://maps.googleapis.com/maps/api/directions/json"+ "?" + str_origin + "&" + str_dest + "&" + "sensor=false";
private String downloadDataFromUrl(String strUrl) throws IOException {
String data = "";
InputStream iStream = null;
HttpsURLConnection urlConnection = null;
try {
URL url = new URL(strUrl);
urlConnection = (HttpsURLConnection) url.openConnection();
urlConnection.connect();
iStream = urlConnection.getInputStream();
BufferedReader br = new BufferedReader(new InputStreamReader(iStream),1024);
StringBuffer sb = new StringBuffer();
String line = "";
while ((line = br.readLine()) != null) {
sb.append(line);
}
data = sb.toString();
br.close();
} catch (Exception e) {
Log.d("Exception", e.toString());
} finally {
iStream.close();
urlConnection.disconnect();
}
return data;
}
Please provide solution. Thanks in advance.
Edit 1:by calling append() it appends Untrusted data to a StringBuilder instance initialized with the default backing-array size (16). This can cause the JVM to over-consume heap memory space.
If you download from an unknown URL, the data can indeed be arbitrary and BufferedReader.readLine() can encounter a line so long the program cannot handle it. This question indicates that limiting BufferedReader line length may not be trivial.
Number of lines can be too big as well, in which case line count check instead of simple null check in the while loop seems to be enough.
Question is why would you allow the user to input an arbitrary URL and download it without checking. The URL can easily be a several GB binary file. Your first line indicates that you intend to use the Google Maps API, which AFAIK does not return excessively large lines, rendering the DOS concern moot (except in some ultrasecure applications, which I do not think Android is suitable to use for).
I'm making an android app for my final project at school.
I only know basic Java and I need to make my app connect to my mysql database.
So I followed this tutorial here with the get method:
https://www.tutorialspoint.com/android/android_php_mysql.htm
Aside from the php part and how it connects and execute the code what I don't understand is this line
StringBuffer sb = new StringBuffer("");
String line="";
while ((line = in.readLine()) != null) {
sb.append(line);
break;
}
in.close();
return sb.toString();
I tried to read this:
https://developer.android.com/reference/java/lang/StringBuffer.html
But I suck at English and reading that won't make me understand what StringBuffer do a bit. I only know that it returns something and it is converted to string type so I think it is the php result.
What I want to know is what does StringBuffer do in the tutorial above? Like they return the value of the php result or not?
And if they do can I use it like this? Because I tried to do like this but got a catch (Exception e) with e.getMessage is null
TextView text2 = (TextView) findViewById(R.id.textView);
text2.setText(sb.toString());
If they do not, how can I set the result of the php value to my textview?
StringBuffer is a way of building a String piece by piece. It is an alternate to manually concatenating strings like this:
String string3 = string0 + string1 + string2;
You would instead do.
stringBuffer.append(string0)
.append(string1)
.append(string2);
Therefore, all it is doing is taking the Strings from in line-by-line and combining it into one String.
Well mate, it depends what result you are expecting you can connect to database for example to send or get some data, and then you need a php file as well.
But the easiest way to connect to db is to use Volley or AsyncTask.
Analise these sample code, it is fully working (but you need a php file which connects with your request:
private class YourTask extends AsyncTask<Void, Void, String> {
#Override
protected String doInBackground(Void... voids) {
String strUrl = "http://YOUR_PLACE_ON_A_SERVER_WHERE_THE_PHP_FILE_IS.php";
URL url = null;
StringBuffer sb = new StringBuffer();
try {
url = new URL(strUrl);
HttpURLConnection connection = (HttpURLConnection) url.openConnection();
connection.connect();
InputStream iStream = connection.getInputStream();
BufferedReader reader = new BufferedReader(new InputStreamReader(iStream));
String line = "";
while ((line = reader.readLine()) != null) {
sb.append(line);
}
reader.close();
iStream.close();
} catch (MalformedURLException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
return sb.toString();
}
//Here you can manage things you want to execute
}
I have a trouble with my HttpsConnection on android.
First of all, no it is not a duplicate. I try almost all the solutions on SO, like changing the keep-alive option or the timeout ( and some of them indeed optimized a part of my code a little bit ) but it is still 5 to 10 times ( probably more ) slower on android than on iOS.
Sending a request to my server takes several seconds on android while it's almost instant on iOS and from a browser. I am sure that the server is not in cause. But it seems that getting the inputstream is terribly slow!
This line:
in=conn.getInputStream();
is the most delaying one, taking several seconds by itself.
My aim is to get a JSON from my server. My code is supposed to be technically as optimized as possible ( and it can probably help some people with HttpsConnection on the same time ):
protected String getContentUrl(String apiURL)
{
StringBuilder builder = new StringBuilder();
String line=null;
String result="";
HttpsURLConnection conn= null;
InputStream in= null;
try {
URL url;
// get URL content
url = new URL(apiURL);
System.setProperty("http.keepAlive", "false");
trustAllHosts();
conn = (HttpsURLConnection) url.openConnection();
conn.setHostnameVerifier(DO_NOT_VERIFY);
conn.setRequestMethod("GET");
conn.setRequestProperty(MainActivity.API_TOKEN, MainActivity.ENCRYPTED_TOKEN);
conn.setRequestProperty("Connection", "close");
conn.setConnectTimeout(1000);
in=conn.getInputStream();
// open the stream and put it into BufferedReader
BufferedReader br = new BufferedReader(new InputStreamReader(in));
while ((line=br.readLine())!= null) {
builder.append(line);
}
result=builder.toString();
//System.out.print(result);
br.close();
} catch (MalformedURLException e) {
result=null;
} catch (IOException e) {
result=null;
} catch (Exception e) {
result=null;
}
finally {
try {
in.close();
}catch(Exception e){}
try {
conn.disconnect();
}catch(Exception e){}
return result;
}
}
However, it keeps taking several seconds.
So I would like to know: is there a way to improve the speed of this API call? The problem is not the server or the JSON parsing but for sure the function above. Thanks a lot.
For my application I need to have the latest data from an webpage that is hosted on a server on my local network.
So I request the latest page with a HTTP GET and when the data is received, I send another request.
With my current implementation I reach around the 100 - 120 ms per request. Is there a possibility to make this quicker because it's the same url that is requested.
For example keep the connection open to the page and grep the latest data without setting up a new connection?
This page is around the 900-1100 bytes.
HTTP get code:
public static String makeHttpGetRequest(String stringUrl) {
try {
URL url = new URL(stringUrl);
HttpURLConnection con = (HttpURLConnection) url.openConnection();
con.setReadTimeout(300);
con.setConnectTimeout(300);
con.setDoOutput(false);
con.setDoInput(true);
con.setChunkedStreamingMode(0);
con.setRequestMethod("GET");
return readStream(con.getInputStream());
} catch (IOException e) {
Log.e(TAG, "IOException when setting up connection: " + e.getMessage());
}
return null;
}
Reading inputstream
private static String readStream(InputStream in) {
BufferedReader reader = null;
StringBuilder total = new StringBuilder();
try {
String line = "";
reader = new BufferedReader(new InputStreamReader(in));
while ((line = reader.readLine()) != null) {
total.append(line);
}
} catch (IOException e) {
Log.e(TAG, "IOException when reading InputStream: " + e.getMessage());
} finally {
if (reader != null) {
try {
reader.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
return total.toString();
}
As I know there isn't an implementation like you are asking for. I've been dealing a lot with http requests and the best thing you can do is your code. There is another thing which need some attention...your connection maybe slow and depending on that connection time can be more or in some cases which I've been dealing a lot the connection's timeout isn't enough big, but that's server problem.
In my opinion you should use what you have now.