[Q] Parse Bluetooth received string - Java for Android App Development

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

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>

Display default contact photo in listView when no photo assigned?

I have a listview which displays the Starred Contacts with photo and name. I've managed so far to display the photos of the contacts which have one. The problem is that when a contact hasn't a photo only the name displayed and not the default contact(from drawables).
Here is the related code:
Code:
Uri queryUri = ContactsContract.Contacts.CONTENT_URI;
String[] projection = new String[] {
ContactsContract.Contacts._ID,
ContactsContract.Contacts.LOOKUP_KEY,
ContactsContract.Contacts.PHOTO_THUMBNAIL_URI,
ContactsContract.Contacts.DISPLAY_NAME,
ContactsContract.Contacts.STARRED};
String selection =ContactsContract.Contacts.STARRED + "='1'";
Cursor cursor = managedQuery(queryUri, projection, selection,null,null);
long id= cursor.getColumnIndex(ContactsContract.Contacts._ID);
Bitmap bitmap = loadContactPhoto(getContentResolver(), id);
if(bitmap!=null){
favIcon.setImageBitmap(bitmap);
}
else{
}
String[] from = {ContactsContract.Contacts.PHOTO_THUMBNAIL_URI, ContactsContract.Contacts.DISPLAY_NAME};
int to[] = new int[]{
R.id.ivDefContact,
R.id.tvContactName
};
ListAdapter adapter = new SimpleCursorAdapter(
this,
R.layout.favs_list_item,
cursor,
from,
to,
CursorAdapter.FLAG_REGISTER_CONTENT_OBSERVER);
final ListView listStarred = (ListView) findViewById(R.id.lvFavs);
listStarred.setAdapter(adapter);
}
public static Bitmap loadContactPhoto(ContentResolver cr, long id) {
Uri uri = ContentUris.withAppendedId(ContactsContract.Contacts.CONTENT_URI, id);
InputStream input = ContactsContract.Contacts.openContactPhotoInputStream(cr, uri);
if (input == null) {
return null;
}
return BitmapFactory.decodeStream(input);
}
How can I achive this?
EDIT:
The app run fine, but I also get these errors on logcat:
I/System.out: resolveUri failed on bad bitmap uri:
E/BitmapFactory: Unable to decode stream: java.io.FileNotFoundException: /: open failed: EISDIR (Is a directory)
Click to expand...
Click to collapse
Did you managed to fix this? I have the same problem.

Grabbing data from a website and putting it into my app?

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.

More secure encryption class using salt

Continuing with the theme from my last thread where I posted a simple class for encrypting strings using the SHA-512 hashing algorithm, here is an improved version that generates a random 20 byte salt to add in with the string to be hashed. This is then hashed providing greater security.
Due to the random generation of the salt each time a string is hashed, this makes it pretty much impossible to get the same hash for a string, therefore once the salt has been generated the first time round it is stored in sharedPreferences for future uses so that you can use it for checking matches etc
Method of converting the bytes to hex string adapted from maybeWeCouldStealAVan's method @ stackoverflow.
Code:
public class Crypto {
final protected static char[] hexArray = "0123456789ABCDEF".toCharArray();
protected static String SHA512(String string, Context context) throws NoSuchAlgorithmException {
MessageDigest md = MessageDigest.getInstance("SHA-512");
String salt = getSalt(context);
md.update(salt.getBytes());
byte[] bytes = md.digest(string.getBytes());
char[] hexChars = new char[bytes.length * 2];
for (int j = 0; j < bytes.length; j++) {
int v = bytes[j] & 0xFF;
hexChars[j * 2] = hexArray[v >>> 4];
hexChars[j * 2 + 1] = hexArray[v & 0x0F];
}
return new String(hexChars);
}
private static String getSalt(Context context) throws NoSuchAlgorithmException {
SharedPreferences preferences = PreferenceManager.getDefaultSharedPreferences(context);
String salt = preferences.getString("salt", null);
if (salt == null) {
byte[] saltBytes = new byte[20];
SecureRandom.getInstance("SHA1PRNG").nextBytes(saltBytes);
salt = new String(saltBytes);
SharedPreferences.Editor editor = preferences.edit();
editor.putString("salt", salt).commit();
}
return salt;
}
}
Usage:
Code:
String example = "example";
try {
example = Crypto.SHA512(example, context);
} catch (NoSuchAlgorithmException e) {
e.printStackTrace();
}
Thanks for sharing, it's quite usefull ! I will include it to my project
Jonny said:
Continuing with the theme from my last thread where I posted a simple class for encrypting strings using the SHA-512 hashing algorithm, here is an improved version that generates a random 20 byte salt to add in with the string to be hashed. This is then hashed providing greater security.
Due to the random generation of the salt each time a string is hashed, this makes it pretty much impossible to get the same hash for a string, therefore once the salt has been generated the first time round it is stored in sharedPreferences for future uses so that you can use it for checking matches etc
Method of converting the bytes to hex string adapted from maybeWeCouldStealAVan's method @ stackoverflow.
Code:
public class Crypto {
final protected static char[] hexArray = "0123456789ABCDEF".toCharArray();
protected static String SHA512(String string, Context context) throws NoSuchAlgorithmException {
MessageDigest md = MessageDigest.getInstance("SHA-512");
String salt = getSalt(context);
md.update(salt.getBytes());
byte[] bytes = md.digest(string.getBytes());
char[] hexChars = new char[bytes.length * 2];
for (int j = 0; j < bytes.length; j++) {
int v = bytes[j] & 0xFF;
hexChars[j * 2] = hexArray[v >>> 4];
hexChars[j * 2 + 1] = hexArray[v & 0x0F];
}
return new String(hexChars);
}
private static String getSalt(Context context) throws NoSuchAlgorithmException {
SharedPreferences preferences = PreferenceManager.getDefaultSharedPreferences(context);
String salt = preferences.getString("salt", null);
if (salt == null) {
byte[] saltBytes = new byte[20];
SecureRandom.getInstance("SHA1PRNG").nextBytes(saltBytes);
salt = new String(saltBytes);
SharedPreferences.Editor editor = preferences.edit();
editor.putString("salt", salt).commit();
}
return salt;
}
}
Usage:
Code:
String example = "example";
try {
example = Crypto.SHA512(example, context);
} catch (NoSuchAlgorithmException e) {
e.printStackTrace();
}
Click to expand...
Click to collapse
Thanks
Gesendet von meinem LG-D855 mit Tapatalk

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.

Categories

Resources