Grabbing data from a website and putting it into my app? - Java for Android App Development

Hi!
My friend talks about this website a lot and said its a great help, and I need some help.
I'm making a app that's grabs images from a couple of websites, and the website updates all the time with new images, and I want my app to dynamically update with it.
I also want my app to precisely filter through the images and put the right images in the right respective folders.
The problem is I don't know how to do this and I can't really find any resources online that can properly explain this (the grabbing data part).
Could someone offer some advice?

google "android parse html" and you will find help. You will need to parse the html for the url of images.
Then you could look over this for an example how to load an image in to an imageview:
http://stackoverflow.com/questions/12172928/android-image-view-from-url

Thanks
Maybe, I'll look into it when I'm done with my exam.
there are thousands of images I want my app to filter through, its gonna take a while to learn
thanks so much for the suggestion

If you know the url of the images you want to fetch beforehand, then use a library such as Picasso by Square Inc., it will allow you to asynchronously load images into your views by calling a single line of code most of the time :
Code:
Picasso.with(context).load("http://i.imgur.com/DvpvklR.png").into(imageView);
Otherwise, if you don't know the urls and want to fetch the images by grabbing the content of the <img src="XXX"/> tags, then you want to look at regular expressions, you could grab the code of the webpage into an InputStream, use a BufferedReader to loop through it line by line and see if it matches your regex, in which case it returns the "XXX", web-crawler style.

Androguide.fr said:
If you know the url of the images you want to fetch beforehand, then use a library such as Picasso by Square Inc., it will allow you to asynchronously load images into your views by calling a single line of code most of the time :
Code:
Picasso.with(context).load("http://i.imgur.com/DvpvklR.png").into(imageView);
Otherwise, if you don't know the urls and want to fetch the images by grabbing the content of the <img src="XXX"/> tags, then you want to look at regular expressions, you could grab the code of the webpage into an InputStream, use a BufferedReader to loop through it line by line and see if it matches your regex, in which case it returns the "XXX", web-crawler style.
Click to expand...
Click to collapse
How to get the html code:
Code:
HttpParams params = new BasicHttpParams();
HttpConnectionParams.setConnectionTimeout(params, 4000);
HttpConnectionParams.setSoTimeout(params, 5000);
HttpClient client = new DefaultHttpClient(params);
HttpGet request = new HttpGet("www.google.com"); //your url goes here
HttpResponse response = client.execute(request);
InputStream is = response.getEntity().getContent();
BufferedReader reader = new BufferedReader(new InputStreamReader(is));
String line = null;
while((line = reader.readLine()) != null) {
//do something with the information
Log.d("line", line);
}

nikwen said:
How to get the html code:
Code:
HttpParams params = new BasicHttpParams();
HttpConnectionParams.setConnectionTimeout(params, 4000);
HttpConnectionParams.setSoTimeout(params, 5000);
HttpClient client = new DefaultHttpClient(params);
HttpGet request = new HttpGet("www.google.com"); //your url goes here
HttpResponse response = client.execute(request);
InputStream is = response.getEntity().getContent();
BufferedReader reader = new BufferedReader(new InputStreamReader(is));
String line = null;
while((line = reader.readLine()) != null) {
//do something with the information
Log.d("line", line);
}
Click to expand...
Click to collapse
Well, while we're at it, here's the code to retrieve the url(s) contained in the src attribute of <img> tags on a website^^
There's probably a more elegant regex but this should work
Code:
// [user=5101348]@nikwen[/user] 's code
// ...
InputStream is = response.getEntity().getContent();
BufferedReader reader = new BufferedReader(new InputStreamReader(is));
String line = null;
ArrayList<String> array = new ArrayList<String>();
while((line = reader.readLine()) != null) {
// If the line matches our regex, extract the url and add it to our ArrayList
String regex = "(*+<img\\s*+src=\")(.+)(\");
if (line.matches(regex)) {
line = line.replaceAll(regex, "$1");
array.add(line);
}
for (int i = 0; i < array.size(); i++) {
Log.d("URL: ", array.get(i));
}
}

Androguide.fr said:
Well, while we're at it, here's the code to retrieve the url(s) contained in the src attribute of <img> tags on a website^^
There's probably a more elegant regex but this should work
Code:
// [user=5101348]@nikwen[/user] 's code
// ...
InputStream is = response.getEntity().getContent();
BufferedReader reader = new BufferedReader(new InputStreamReader(is));
String line = null;
ArrayList<String> array = new ArrayList<String>();
while((line = reader.readLine()) != null) {
// If the line matches our regex, extract the url and add it to our ArrayList
String regex = "(*+<img\\s*+src=\")(.+)(\");
if (line.match(regex)) {
line = line.replaceAll(regex, "$1");
array.add(line);
}
for (int i = 0; i < array.size(); i++) {
Log.d("URL: ", array.get(i));
}
}
Click to expand...
Click to collapse
What's more performant? The contains or the matches method? I guess the contains method, right?
(However, I don't know a way to use the contains method here.)

nikwen said:
What's more performant? The contains or the match method? I guess the contains method, right?
(However, I don't know a way to use the contains method here.)
Click to expand...
Click to collapse
I really couldn't tell which one is faster, it's a good question though.
EDIT: you made me realize I made a typo, the method is .matches() and not .match(), correcting the previous post.

Androguide.fr said:
Well, while we're at it, here's the code to retrieve the url(s) contained in the src attribute of <img> tags on a website^^
There's probably a more elegant regex but this should work
Code:
// [user=5101348]@nikwen[/user] 's code
// ...
InputStream is = response.getEntity().getContent();
BufferedReader reader = new BufferedReader(new InputStreamReader(is));
String line = null;
ArrayList<String> array = new ArrayList<String>();
while((line = reader.readLine()) != null) {
// If the line matches our regex, extract the url and add it to our ArrayList
String regex = "(*+<img\\s*+src=\")(.+)(\");
if (line.matches(regex)) {
line = line.replaceAll(regex, "$1");
array.add(line);
}
for (int i = 0; i < array.size(); i++) {
Log.d("URL: ", array.get(i));
}
}
Click to expand...
Click to collapse
Can you explain what is happening here in the String regex line as well as the line = line.replaceAll(), please?

Shizznizz said:
Can you explain what is happening here in the String regex line as well as the line = line.replaceAll(), please?
Click to expand...
Click to collapse
Sure, my regular expression is here divided into 3 groups (each between parenthesis), let's run through them:
*+<img\\s*+src=\"
This basically says "match any character any number of times (*+) followed by <img and a blankspace (\s escaped twice as it's in a string), followed by any character any number of times again (*+, to cover cases where other attributes are placed before src), followed by src="
.+
This corresponds to the actual URL we are looking for, it matches any character any number of times except 0 times (.+)
\"
Self explanatory, the closing quote for our src="X" attribute, escaped as contained within a String
The grouping comes into play in the line.replaceAll(), basically, it says replace the whole line string with group n°2 of our regex, which is our URL.
When grouping a regex, the second parameter of replaceAll() can be set as $X, where X is the target group's 0-based index, in our case the second group so $1
So, to conclude, the schema of the snippet is:
Grab the whole html code of the webpage
Loop through it line by line
If a line contains a <img> tag, retrieve the string contained within the src attribute of its <img> tag and add it to an array
Otherwise, go to next line and repeat previous step

Androguide.fr said:
Sure, my regular expression is here divided into 3 groups (each between parenthesis), let's run through them:
*+<img\\s*+src=\"
This basically says "match any character any number of times (*+) followed by <img and a blankspace (\s escaped twice as it's in a string), followed by any character any number of times again (*+, to cover cases where other attributes are placed before src), followed by src="
.+
This corresponds to the actual URL we are looking for, it matches any character any number of times except 0 times (.+)
\"
Self explanatory, the closing quote for our src="X" attribute, escaped as contained within a String
The grouping comes into play in the line.replaceAll(), basically, it says replace the whole line string with group n°2 of our regex, which is our URL.
When grouping a regex, the second parameter of replaceAll() can be set as $X, where X is the target group's 0-based index, in our case the second group so $1
So, to conclude, the schema of the snippet is:
Grab the whole html code of the webpage
Loop through it line by line
If a line contains a <img> tag, retrieve the string contained within the src attribute of its <img> tag and add it to an array
Otherwise, go to next line and repeat previous step
Click to expand...
Click to collapse
That was very helpful. Thank you!

Androguide.fr said:
I really couldn't tell which one is faster, it's a good question though.
EDIT: you made me realize I made a typo, the method is .matches() and not .match(), correcting the previous post.
Click to expand...
Click to collapse
Ok, so I did some benchmarking:
Code:
import java.util.ArrayList;
public class Benchmark {
public static void main(String[] args) {
ArrayList<String> list = new ArrayList<String>();
ArrayList<String> list2 = new ArrayList<String>();
for (int i = 0; i < 10000000; i++) {
String s = String.valueOf(i);
if ((i % 78) == 0) {
s += "test" + i;
}
list.add(s);
}
list2.addAll(list);
long time = System.currentTimeMillis();
for (String line: list) {
if (line.matches("(.*)test(.*)")) {
System.out.println(line);
}
}
long timeMatches = System.currentTimeMillis();
try {
Thread.sleep(5000);
} catch (InterruptedException e) {
e.printStackTrace();
}
long time2 = System.currentTimeMillis();
for (String line: list2) {
if (line.contains("test")) {
System.out.println(line);
}
}
long timeContains = System.currentTimeMillis();
System.out.println("Time for matches(): " + (timeMatches - time));
System.out.println("Time for contains(): " + (timeContains - time2));
}
}
Some results:
Code:
Time for matches(): 7116
Time for contains(): 893
Time for matches(): 6973
Time for contains(): 1027
Time for matches(): 8264
Time for contains(): 858
Time for matches(): 8098
Time for contains(): 1216
Even if it is no perfect benchmark, you can see the (big) difference.
The contains method is about 8 times faster than matches with a regex that does the same.
Remember, I used a very simple regex. So it should be even slower for more complicated ones.
Of course, it just shows what is faster on the desktop computer. However, it should be the same on an Android device. There's such a big difference in performance.
In my opinion the result makes sense.
The contains method just checks whether it can find the char array (which a String is for the computer) in another.
The matches method has to interpret the regex first. Afterwards, it has to do lots of calculation to check whether the String matches the regex.

nikwen said:
Ok, so I did some benchmarking:
Code:
import java.util.ArrayList;
public class Benchmark {
public static void main(String[] args) {
ArrayList<String> list = new ArrayList<String>();
ArrayList<String> list2 = new ArrayList<String>();
for (int i = 0; i < 10000000; i++) {
String s = String.valueOf(i);
if ((i % 78) == 0) {
s += "test" + i;
}
list.add(s);
}
list2.addAll(list);
long time = System.currentTimeMillis();
for (String line: list) {
if (line.matches("(.*)test(.*)")) {
System.out.println(line);
}
}
long timeMatches = System.currentTimeMillis();
try {
Thread.sleep(5000);
} catch (InterruptedException e) {
e.printStackTrace();
}
long time2 = System.currentTimeMillis();
for (String line: list2) {
if (line.contains("test")) {
System.out.println(line);
}
}
long timeContains = System.currentTimeMillis();
System.out.println("Time for matches(): " + (timeMatches - time));
System.out.println("Time for contains(): " + (timeContains - time2));
}
}
Some results:
Code:
Time for matches(): 7116
Time for contains(): 893
Time for matches(): 6973
Time for contains(): 1027
Time for matches(): 8264
Time for contains(): 858
Time for matches(): 8098
Time for contains(): 1216
Even if it is no perfect benchmark, you can see the (big) difference.
The contains method is about 8 times faster than matches with a regex that does the same.
Remember, I used a very simple regex. So it should be even slower for more complicated ones.
Of course, it just shows what is faster on the desktop computer. However, it should be the same on an Android device. There's such a big difference in performance.
In my opinion the result makes sense.
The contains method just checks whether it can find the char array (which a String is for the computer) in another.
The matches method has to interpret the regex first. Afterwards, it has to do lots of calculation to check whether the String matches the regex.
Click to expand...
Click to collapse
Awesome, thanks for taking the time to benchmark it.
Yeah, it does make sense that matches() is slower because of the parsing computation.
But as you said, in this kind of case you can't really use anything else than a regex, and thus you have to use matches()
Either way, the difference shouldn't be noticeable to the human eye I guess, regular expressions can only be so long.

Androguide.fr said:
Awesome, thanks for taking the time to benchmark it.
Yeah, it does make sense that matches() is slower because of the parsing computation.
But as you said, in this kind of case you can't really use anything else than a regex, and thus you have to use matches()
Either way, the difference shouldn't be noticeable to the human eye I guess, regular expressions can only be so long.
Click to expand...
Click to collapse
Yeah, it's not noticeable. It takes about 8 seconds for 10000000 regexes. Thats 0.0000008 seconds per regex.

Related

Newbie url text download problem

Hi guys,
I am totally new at this. I mean completely raw .
I successfully put together a searchlight project by following a tutorial on youtube.
Now I want to do some work on a project that will fetch information from my employers website into the app. This information will be inform of text and images.
Here's the code I'm using in my attempt to read the remote text:
Code:
try {
URL url = new URL( "fullpath-url-to-file-dot-php" );
URLConnection conn = url.openConnection();
// Get the response
BufferedReader rd = new BufferedReader(new InputStreamReader(conn.getInputStream()));
String line = "";
while ((line = rd.readLine()) != null) {
Message lmsg;
lmsg = new Message();
lmsg.obj = line;
lmsg.what = 0;
Context context = getApplicationContext();
CharSequence text = "Hello toast! "+lmsg;
int duration = Toast.LENGTH_LONG;
Toast toast = Toast.makeText(context, text, duration);toast.show();
}
} catch (IOException e) {
// TODO Auto-generated catch block
//e.printStackTrace();
Context context = getApplicationContext();
CharSequence text = "error!";
int duration = Toast.LENGTH_LONG;
Toast toast = Toast.makeText(context, text, duration);toast.show();
}
I admit I barely know what I am doing. My attempt to download a simple line of text from a website url keeps failing.
Anyway, Can you guys give me an idea what I am doing wrong and what I should be doing instead?
Thanks
Update
I found out what the nature of the exception is.
It's a
Code:
java.net.socketexception: permission denied
exception.
Can anyone please shed some light on this for me ?
Did you add the internet permission to your manifest file?
Should be something like
<uses-permission>android.permission.INTERNET</uses-permission>

Http request incomplete response

hi folks,
here is the code and I've seen basically the same thing from several sources, I compare with them all and it doesn't seem to be any problem with it:
Code:
private static String HttpCall(String url) throws URISyntaxException,
IOException {
BufferedReader in = null;
try {
HttpClient client = new DefaultHttpClient();
HttpGet request = new HttpGet();
request.setURI(new URI(url));
HttpResponse response = client.execute(request);
in = new BufferedReader(new InputStreamReader(response.getEntity()
.getContent()));
StringBuffer sb = new StringBuffer("");
String line = "";
String NL = System.getProperty("line.separator");
while ((line = in.readLine()) != null) {
sb.append(line + NL);
}
in.close();
Log.d("Pristina", "URL: " + url);
Log.d("Pristina", sb.toString());
return sb.toString();
} finally {
if (in != null) {
in.close();
}
}
}
I'm pretty much getting an HttpClient, HttpGet and HttpResponse, getting the InputStream out of it and returning it as a String... it was supposed to be piece of cake.
I'm using this to get a JSON object from a Wordpress blog which have the JSON plugin installed.
I tried the URL on my desktop chrome browser and the response is absolutely perfect, no problems. Most of the time the response from this code is fine too, it was working fine a few days ago... but now the response comes incomplete... I mean.. the string out of it is going fine as a JSON object and all of a sudden it's over. It end's as:
Code:
"width" : 500,
"height" : 500
}
}
}, {
"id" : 37525,
"url" :
no if's no buts... it's giving me the correct info and it says it will give me a url and that's it... the string is over!
From stack overflow someone suggested using EntityUtils.toString(response.getEntity()); and I still can't get a valid response. In this blogpost http://blog.dahanne.net/2009/08/16/how-to-access-http-resources-from-android/ the guy shows a few ways of doing an Http request I tried the 1st one and the final string I get it's still incomplete.
I would normally think it's something wrong with the JSONplugging installed on the server.. but the response is just fine from Chrome browser.
any ideas ??? I really don't know what else to do.
up!
anyone? please.... I've been desperate trying to find a solution for days now!
Just to "close" the post.
at the end was a mix of LogCat only showing a mix of X chars and a problem in a completely different point in my parser!
also at the end I found out this:
Code:
ret = new String(EntityUtils.toString(entity));
being a much cleaner code than the stupid loops.
if any forum moderator sees this feel free to close the thread.

[Q] Parse Bluetooth received string

Hi, I have a newbie question..
I have modified the bluetoothChat example to get serial data from my pc to my phone over bluetooth.
The code uses the following code to keep listening for incoming data:
Code:
public void run() {
Log.i(TAG, "BEGIN mConnectedThread");
byte[] buffer = new byte[1024];
int bytes = 0;
// byte x = 0;
// Keep listening to the InputStream while connected
while (true) {
try {
// Read from the InputStream
bytes = mmInStream.read(buffer);
// Send the obtained bytes to the UI Activity
mHandler.obtainMessage(BluetoothChat.MESSAGE_READ, bytes, -1, buffer)
.sendToTarget();
} catch (IOException e) {
Log.e(TAG, "disconnected", e);
connectionLost();
// Start the service over to restart listening mode
BluetoothChatService.this.start();
break;
}
}
}
And in the MainActivity the following code when data is received:
Code:
case MESSAGE_READ:
byte [] readBuf;
//readBuf = (byte[]) msg.obj;
readBuf = (byte[]) msg.obj;
String readMessage = new String(readBuf, 0, msg.arg1); // create string from bytes array
messageString = messageString + readMessage;
if (messageString.length()<10){
TextView text = (TextView) findViewById(R.id.textView1); // Display output
text.setText("<10....");
break;
}
sb.append(readMessage); // append string
int endOfLineIndex = sb.indexOf("#"); // determine the end-of-line
if (endOfLineIndex > 0) { // if end-of-line,
String sbprint = sb.substring(0, endOfLineIndex); // extract string
sb.delete(0, sb.length()); // and clear
TextView text = (TextView) findViewById(R.id.textView1); // Display output
text.setText(sbprint);
mConversationArrayAdapter.add(mConnectedDeviceName+": " + readMessage);
}
break;
As shown i have added a endOfLineIndex loop to find the end of the received string and show the received string in a textfield. The problem with my code is when sending a string like "0123456789#" the shown text in the textView1 is mostly not the send string.. I get strings like 0123,4560123456789, etc.. Somehow there is still data in the buffer i quess.
Is there a way to clear or ignore the received data and only parse the wanted string form the buffer? If this is possible i can add a start identifier to the string..
The main goal is too parse a string like: #150,000,001,000,0.0,-0.1,40.3,144.0,001,OKE where each value is a variable which needed to be placed in a textview.
Thanks for any suggestions!
Kind regards,
Bas
This one "0123456789#" should return "0123456789". Does it?
You invoke substring().
Quote from the docs:
The substring begins at the specified beginIndex and extends to the character at index endIndex - 1.
Click to expand...
Click to collapse
(http://docs.oracle.com/javase/1.4.2/docs/api/java/lang/String.html#substring(int, int))
That means that the last character (the #) is missed out.
Thanks Nikwen,
I do miss out the end off string character #. The problem is i get different strings out of the buffer... If i send 0123456789# with a one second interval i get different results.. sometimes i get the string like expected which is 0123456789. but most of the time i get results like 0123, 456789,12,1,etc etc. it looks like the buffer is not cleared or something

Java is too complex for begginer lovers

I love Android. I want to learn to develop apps. I keep reading tutorials. I got dissapointed and read about HTML frameworks (phonegap, etc). I came back to Android Native Java. I want to learn from the roots. However, some things discourages me....
All this part of the code is just for making a request to the Openweather API and get the json data (plus a little debugging stuff); which in Python or similar languages you only have to care about
- importing the library that handles http requests
- make the request in one function and save it into a json object
Code:
HttpURLConnection urlConnection = null;
BufferedReader reader = null;
// Will contain the raw JSON response as a string.
String forecastJsonStr = null;
String format = "json";
String units = "metric";
int numDays = 7;
try {
final String FORECAST_BASE_URL =
"<the-domain>/data/2.5/forecast/daily?";
final String QUERY_PARAM = "q";
final String FORMAT_PARAM = "mode";
final String UNITS_PARAM = "units";
final String DAYS_PARAM = "cnt";
Uri builtUri = Uri.parse(FORECAST_BASE_URL).buildUpon()
.appendQueryParameter(QUERY_PARAM, params[0])
.appendQueryParameter(FORMAT_PARAM, format)
.appendQueryParameter(UNITS_PARAM, units)
.appendQueryParameter(DAYS_PARAM, Integer.toString(numDays))
.build();
URL url = new URL(builtUri.toString());
Log.v(LOG_TAG, "Built URI " + builtUri.toString());
// 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.
return null;
}
reader = new BufferedReader(new InputStreamReader(inputStream));
String line;
while ((line = reader.readLine()) != null) {
buffer.append(line + "\n");
}
if (buffer.length() == 0) {
// Stream was empty. No point in parsing.
return null;
}
forecastJsonStr = buffer.toString();
Log.v(LOG_TAG, "Forecast string: " + forecastJsonStr);
} catch (IOException e) {
Log.e(LOG_TAG, "Error ", e);
// If the code didn't successfully get the weather data, there's no point in attemping
// to parse it.
return null;
} finally {
if (urlConnection != null) {
urlConnection.disconnect();
}
if (reader != null) {
try {
reader.close();
} catch (final IOException e) {
Log.e(LOG_TAG, "Error closing stream", e);
}
}
}
This is the complete Class:
Code:
public class FetchWeatherTask extends AsyncTask<String, Void, String[]> {
private final String LOG_TAG = FetchWeatherTask.class.getSimpleName();
/* The date/time conversion code is going to be moved outside the asynctask later,
* so for convenience we're breaking it out into its own method now.
*/
private String getReadableDateString(long time){
// Because the API returns a unix timestamp (measured in seconds),
// it must be converted to milliseconds in order to be converted to valid date.
Date date = new Date(time * 1000);
SimpleDateFormat format = new SimpleDateFormat("E, MMM d");
return format.format(date).toString();
}
/**
* Prepare the weather high/lows for presentation.
*/
private String formatHighLows(double high, double low) {
// For presentation, assume the user doesn't care about tenths of a degree.
long roundedHigh = Math.round(high);
long roundedLow = Math.round(low);
String highLowStr = roundedHigh + "/" + roundedLow;
return highLowStr;
}
/**
* Take the String representing the complete forecast in JSON Format and
* pull out the data we need to construct the Strings needed for the wireframes.
*
* Fortunately parsing is easy: constructor takes the JSON string and converts it
* into an Object hierarchy for us.
*/
private String[] getWeatherDataFromJson(String forecastJsonStr, int numDays)
throws JSONException {
// These are the names of the JSON objects that need to be extracted.
final String OWM_LIST = "list";
final String OWM_WEATHER = "weather";
final String OWM_TEMPERATURE = "temp";
final String OWM_MAX = "max";
final String OWM_MIN = "min";
final String OWM_DATETIME = "dt";
final String OWM_DESCRIPTION = "main";
JSONObject forecastJson = new JSONObject(forecastJsonStr);
JSONArray weatherArray = forecastJson.getJSONArray(OWM_LIST);
String[] resultStrs = new String[numDays];
for(int i = 0; i < weatherArray.length(); i++) {
// For now, using the format "Day, description, hi/low"
String day;
String description;
String highAndLow;
// Get the JSON object representing the day
JSONObject dayForecast = weatherArray.getJSONObject(i);
// The date/time is returned as a long. We need to convert that
// into something human-readable, since most people won't read "1400356800" as
// "this saturday".
long dateTime = dayForecast.getLong(OWM_DATETIME);
day = getReadableDateString(dateTime);
// description is in a child array called "weather", which is 1 element long.
JSONObject weatherObject = dayForecast.getJSONArray(OWM_WEATHER).getJSONObject(0);
description = weatherObject.getString(OWM_DESCRIPTION);
// Temperatures are in a child object called "temp". Try not to name variables
// "temp" when working with temperature. It confuses everybody.
JSONObject temperatureObject = dayForecast.getJSONObject(OWM_TEMPERATURE);
double high = temperatureObject.getDouble(OWM_MAX);
double low = temperatureObject.getDouble(OWM_MIN);
highAndLow = formatHighLows(high, low);
resultStrs[i] = day + " - " + description + " - " + highAndLow;
}
for (String s : resultStrs) {
Log.v(LOG_TAG, "Forecast entry: " + s);
}
return resultStrs;
}
@Override
protected String[] doInBackground(String... params) {
// If there's no zip code, there's nothing to look up. Verify size of params.
if (params.length == 0) {
return null;
}
// 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;
String format = "json";
String units = "metric";
int numDays = 7;
try {
// Construct the URL for the OpenWeatherMap query
// Possible parameters are avaiable at OWM's forecast API page
final String FORECAST_BASE_URL =
"<the-domain>/data/2.5/forecast/daily?";
final String QUERY_PARAM = "q";
final String FORMAT_PARAM = "mode";
final String UNITS_PARAM = "units";
final String DAYS_PARAM = "cnt";
Uri builtUri = Uri.parse(FORECAST_BASE_URL).buildUpon()
.appendQueryParameter(QUERY_PARAM, params[0])
.appendQueryParameter(FORMAT_PARAM, format)
.appendQueryParameter(UNITS_PARAM, units)
.appendQueryParameter(DAYS_PARAM, Integer.toString(numDays))
.build();
URL url = new URL(builtUri.toString());
Log.v(LOG_TAG, "Built URI " + builtUri.toString());
// 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.
return 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.
return null;
}
forecastJsonStr = buffer.toString();
Log.v(LOG_TAG, "Forecast string: " + forecastJsonStr);
} catch (IOException e) {
Log.e(LOG_TAG, "Error ", e);
// If the code didn't successfully get the weather data, there's no point in attemping
// to parse it.
return null;
} finally {
if (urlConnection != null) {
urlConnection.disconnect();
}
if (reader != null) {
try {
reader.close();
} catch (final IOException e) {
Log.e(LOG_TAG, "Error closing stream", e);
}
}
}
try {
return getWeatherDataFromJson(forecastJsonStr, numDays);
} catch (JSONException e) {
Log.e(LOG_TAG, e.getMessage(), e);
e.printStackTrace();
}
// This will only happen if there was an error getting or parsing the forecast.
return null;
}
}
I mean, I know this code can be reduced, but I'm angry about the way it works. Everything needs to be passed to another object! And even rembember all those castings! Castings everywhere!
- The builded URI to the URL.
- The URL to the HttpConection variable.
- Once you connect, save that into the InputStream.
- Make a StringBuffer because we are going to send line by line everything.
- Then create the reader = new BufferedReader(new InputStreamReader(inputStream)).
- Append the lines to the buffer and return if it's ok.
- Else catch all the errors and be sure to close all the connections.
Damn Java !
Forgive me. You'll hate me.
Java is readable, that's the truth... but don't tell me that it is easy for a normal person.
Am I the only one?
If you are a beginner and will straight move to these classes. You will obviously find Java difficult. But Java is very easy if you move step by step from start
Sent from my XT1033 using XDA Premium 4 mobile app
---------- Post added at 04:18 PM ---------- Previous post was at 04:16 PM ----------
And that library also does the same thing inside. Only difference is, your work is already done by author of the library.
Sent from my XT1033 using XDA Premium 4 mobile app
Java is definitely a very verbose language but it's also widely used and so you will find many libraries that do tasks like grab JSON data from a service that have already been implemented for you
manwoman said:
Damn Java !
Forgive me. You'll hate me.
Java is readable, that's the truth... but don't tell me that it is easy for a normal person.
Am I the only one?
Click to expand...
Click to collapse
I don't think you're the only one. It's easy to get scared away by the many too verbose examples available, the key is to look at what you're trying to achieve and then break it up into those parts.
Your code listing is (I think) an attempt to show all steps to get the forecast data, but if that would have been broken up into smaller steps I don't think you'd look at it as quite as bad.
You would then have methods like
Code:
URL getForecastUrl(String parameter);
Code:
BufferedReader getUrl(URL url) { }
Code:
String readAll(BufferedReader reader) {}
Each of which would have had something like 6-7 lines of simple, cohesive code.
I understand your point, but in this particular scenario I think you're the victim of a poorly structured code sample rather than a too verbose language.
If you think the default implementation is too complicated, here are also many java libraries which will make your life easier.

Help with Apple WeatherKit

I hope someone can help me.
I'm having trouble getting an Apple WeatherKit REST request working. I'm trying to follow all of the requirements listed on https://developer.apple.com/documen...equest_authentication_for_weatherkit_rest_api, but I still get a 403 response code -- and I can't locate any Java samples to follow. I've been sweating this for weeks and haven't gotten anywhere.
Here's what I have:
URL url = new URL ("https://weatherkit.apple.com/api/v1/weather/en/40.75/-73.00?dataSets=currentWeather&timezone=Europe/London");
PrivateKey pkey = getPrivateKey ("AuthKey_CXXXXXXXXX.p8");
String jwts = getJwtsString (pkey);
HttpURLConnection conn = getConnection (url, jwts);
conn.connect();
int responsecode = conn.getResponseCode();
Just in case I've got something wrong, here are the three functions I'm calling. First, the one that creates the PrivateKey from the p8 file (I'm pretty sure this one is OK):
private PrivateKey getPrivateKey (String filename) {
PrivateKey privateKey = null;
try {
AssetManager assetManager = this.getAssets();
InputStream stream = assetManager.open(filename);
byte[] bytes = new byte[stream.available()];
int bytesRead = stream.read(bytes);
byte[] pkcs8EncodedKey = new byte[0];
pkcs8EncodedKey = Base64.getDecoder().decode(bytes);
KeyFactory factory = KeyFactory.getInstance("EC");
privateKey = factory.generatePrivate(new PKCS8EncodedKeySpec(pkcs8EncodedKey));
} catch (Exception e) { }
return privateKey;
}
Next, creating the JWTS string:
private String getJwtsString(PrivateKey privateKey) {
long t1 = System.currentTimeMillis();
return Jwts.builder()
.setHeaderParam ("alg", "ES256")
.setHeaderParam ("kid", "CXXXXXXXXX")
.setHeaderParam ("id", "QXXXXXXXXX.com.mydomain.myproject")
.claim ("iss", "Q5DC438ZG4")
.claim ("iat", t1)
.claim ("exp", t1 + 60000)
.claim ("sub", "com.mydomain.myproject") // obviously, replaced with my project info
.signWith (privateKey, SignatureAlgorithm.ES256)
.compact ();
}
And finally, creating the connection:
private HttpURLConnection getConnection(URL url, String jws) {
HttpURLConnection conn = (HttpURLConnection) Objects.requireNonNull(url).openConnection();
conn.setRequestMethod ("GET")
conn.setRequestProperty ("Authorization", "Bearer "+ jws);
conn.setRequestProperty ("Content-Type", "application/x-www-form-urlencoded");
conn.setRequestProperty ("Content-Language", "en-US");
conn.setUseCaches (false);
conn.setDoInput (true);
conn.setDoOutput (true);
conn.setConnectTimeout (30000); //set timeout to 30 seconds
return conn;
}
Obviously, this is the first time I've tried creating an authenticated http call, so I wouldn't be at all surprised if this is wrong.
Can anybody supply some sample code that I could follow?
Thanks in advance...

Categories

Resources