Encoding Issue with HttpUrlConnection in Android - android

I want to send an XML message to a server from my Android Mobile app via HTTP post.
I tried it with HttpUrlConnection, following these steps:
URL url = new URL(vURL);
HttpUrlConnection conn = (HttpURLConnection) url.openConnection();
conn.setDoInput(true);
conn.setDoOutput(true);
// Adding headers (code removed)
conn.setRequestProperty("Content-Type", "text/xml; charset=utf-16");
OutputStream out = new BufferedOutputStream(conn.getOutputStream());
// Adding XML message to the connection output stream
// I have removed exception handling to improve readability for posting it here
out.write(pReq.getBytes()); // here pReq is the XML message in String
out.close();
conn.connect();
Once I get the response, the stream reading part is in done this manner:
BufferedReader in = null;
StringBuffer sb;
String result = null;
try {
InputStreamReader isr = new InputStreamReader(is);
// Just in case, I've also tried:
// new InputStreamReader(is, "UTF-16");
// new InputStreamReader(is, "UTF-16LE");
// new InputStreamReader(is, "UTF-16BE");
// new InputStreamReader(is, "UTF-8");
in = new BufferedReader(isr);
sb = new StringBuffer("");
String line = "";
while ((line = in.readLine()) != null)
sb.append(line);
in.close();
result = sb.toString();
} catch (Exception e) {
e.printStackTrace();
}
Now the result string I get is in some unreadable format/encoding.
When I try the same thing with HttpClient it works correctly. Here is the streaming reading part once I get an HttpResponse after the HttpClient.execute call:
BufferedReader in = null;
InputStream is;
StringBuffer sb;
String decompbuff = null;
try {
is = pResponse.getEntity().getContent();
InputStreamReader isr = new InputStreamReader(is);
in = new BufferedReader(isr);
// Prepare the String buffer
sb = new StringBuffer("");
String line = "";
while ((line = in.readLine()) != null)
sb.append(line);
in.close();
// gZip decompression of response. Note: message was compressed before
// posting it via HttpClient (Posting code is not mentioned here)
decompbuff = Decompress(sb.toString());
} catch (Exception e) {
e.printStackTrace();
}
return decompbuff;
Some help is appreciated in understanding the problem.

One (severe) problem could be that you're ignoring the encoding of input and output.
Input
conn.setRequestProperty("Content-Type", "text/xml; charset=utf-16");
OutputStream out = new BufferedOutputStream(conn.getOutputStream());
// Adding XML message to the connection output stream
// I have removed exception handling to improve readability for posting it here
out.write(pReq.getBytes()); // <-- you use standard platform encoding
out.close();
better:
out.write(pReq.getBytes("UTF-16"));
Output
You probably ignored compression, which would better look like this (taken from DavidWebb):
static InputStream wrapStream(String contentEncoding, InputStream inputStream)
throws IOException {
if (contentEncoding == null || "identity".equalsIgnoreCase(contentEncoding)) {
return inputStream;
}
if ("gzip".equalsIgnoreCase(contentEncoding)) {
return new GZIPInputStream(inputStream);
}
if ("deflate".equalsIgnoreCase(contentEncoding)) {
return new InflaterInputStream(inputStream, new Inflater(false), 512);
}
throw new RuntimeException("unsupported content-encoding: " + contentEncoding);
}
// ...
InputStream is = wrapStream(conn.getContentEncoding(), is);
InputStreamReader isr = new InputStreamReader(is, "UTF-16");
in = new BufferedReader(isr);
sb = new StringBuffer("");
String line = "";
while ((line = in.readLine()) != null)
sb.append(line); // <-- you're swallowing linefeeds!
in.close();
result = sb.toString();
It would be better to let the XML-Parser consume your InputStream directly. Don't create a JAVA string, but let the parser scan the bytes. It will automatically detect the encoding of the XML.
Generally there might be still an issue, because we don't know what type of UTF-16 you use. Can be BigEndian or LittleEndian. That's why I asked, if you really need UTF-16. If you don't have to treat with some asian languages, UTF-8 should be more efficient and easier to use.
So the "solution" I gave you is not guaranteed to work - you have to fiddle with UTF-16 BE/LE a bit and I wish you good luck and patience.
Another remark: in your example above you first construct the String and then Decompress it. That is the wrong order. The stream comes compressed (gzip, deflate) and must be decompressed first. Then you get the String.

Related

Loading JSON in browser works, in Android it's garbage

So I'm trying to load this JSON in Android from here, and have tried both Volley and regular HTTP requests. The page (eventually) loads fine as UTF-8 JSON and it looks fine. However, in android, I get garbage like this:
Checked the document.characterSet, it's UTF-8.
Example as Volley (trimmed out some code, so brackets may not be exact):
final JsonObjectRequest jsonObjectRequest = new JsonObjectRequest(url, new Response.Listener<JSONObject>() {
#Override
public void onResponse(JSONObject response) {
}
}, new Response.ErrorListener() {
#Override
public void onErrorResponse(VolleyError ex) {
Log.e("LOG", ex.toString());
}
});
requestQueue.add(jsonObjectRequest);
Example as regular HTTP GET:
HttpURLConnection urlConnection = null;
URL url = new URL(urlString);
urlConnection = (HttpURLConnection) url.openConnection();
urlConnection.setRequestMethod("GET");
urlConnection.setReadTimeout(10000 /* milliseconds */);
urlConnection.setConnectTimeout(2500 /* milliseconds */);
urlConnection.setDoOutput(true);
urlConnection.connect();
String UTF8 = "UTF-8";
int BUFFER_SIZE = 8192;
BufferedReader br = new BufferedReader(new InputStreamReader(url.openStream(), UTF8), BUFFER_SIZE);
StringBuilder sb = new StringBuilder();
String line;
while ((line = br.readLine()) != null) {
sb.append(line + "\n");
}
br.close();
String jsonString = sb.toString();
urlConnection.disconnect();
urlConnection = null;
br = null;
sb = null;
if (jsonString != null &&
jsonString.length() > 0) {
return new JSONObject(jsonString);
}
Both give garbage responses. What am I missing? I'm able to access other data on other sites.
The content is compressed using zlib. See header:
Content-Encoding: deflate
You'll have to read the raw bytes and decompress them before attempting to parse as JSON. Looks like Android provides native support for zlib via the Deflater class.
Note that further, readers by default use the system default character encoding. Unless your system default happens to match that of the delivered content, you'll need to tell the system how to decode the charset. The correct thing is to read raw bytes from a stream, then turn the bytes into a string using the proper character encoding,
byte[] buffer = new byte[1024];
int c;
ByteArrayOutputStream baos = new ByteArrayOutputStream();
while ((c = inputStream.read(buffer)) > 0) {
baos.write(buffer, 0, c);
}
String json = new String(baos.toByteArray(), "UTF-8"); // assuming the encoding if UTF-8
You can either know the encoding ahead of time, or parse it from the Content-Type header. I looked at the response from the provided URL and it does not specify a charset, so you'll have to hardcode the known value.
EDIT: apparently you can do this with a reader, although I haven't tried it:
Reader r = new InputStreamReader(inputStream, "UTF-8");

How to download String file which contain special characters of slovenia

I am trying to download the json file which contains slovenian characters,While downloading json file as a string I am getting special character as specified below in json data
"send_mail": "Po�lji elektronsko sporocilo.",
"str_comments_likes": "Komentarji, v�ecki in mejniki",
Code which I am using
URL url = new URL(f_url[0]);
URLConnection conection = url.openConnection();
conection.connect();
try {
InputStream input1 = new BufferedInputStream(url.openStream(), 300);
String myData = "";
BufferedReader r = new BufferedReader(new InputStreamReader(input1));
StringBuilder totalValue = new StringBuilder();
String line;
while ((line = r.readLine()) != null) {
totalValue.append(line).append('\n');
}
input1.close();
String value = totalValue.toString();
Log.v("To Check Problem from http paramers", value);
} catch (Exception e) {
Log.v("Exception Character Isssue", "" + e.getMessage());
}
I want to know how to get characters downloaded properly.
You need to encode string bytes to UTF-8. Please check following code :
String slovenianJSON = new String(value.getBytes([Original Code]),"utf-8");
JSONObject newJSON = new JSONObject(reconstitutedJSONString);
String javaStringValue = newJSON.getString("content");
I hope it will help you!
Decoding line in while loop can work. Also you should add your connection in try catch block in case of IOException
URL url = new URL(f_url[0]);
try {
URLConnection conection = url.openConnection();
conection.connect();
InputStream input1 = new BufferedInputStream(url.openStream(), 300);
String myData = "";
BufferedReader r = new BufferedReader(new InputStreamReader(input1));
StringBuilder totalValue = new StringBuilder();
String line;
while ((line = r.readLine()) != null) {
line = URLEncoder.encode(line, "UTF8");
totalValue.append(line).append('\n');
}
input1.close();
String value = totalValue.toString();
Log.v("To Check Problem from http paramers", value);
} catch (Exception e) {
Log.v("Exception Character Isssue", "" + e.getMessage());
}
It's not entirely clear why you're not using Android's JSONObject class (and related classes). You can try this, however:
String str = new String(value.getBytes("ISO-8859-1"), "UTF-8");
But you really should use the JSON libraries rather than parsing yourself
When creating the InputStreamReader at this line:
BufferedReader r = new BufferedReader(new InputStreamReader(input1));
send the charset to the constructor like this:
BufferedReader r = new BufferedReader(new InputStreamReader(input1), Charset.forName("UTF_8"));
problem is in character set
as per Wikipedia Slovene alphabet supported by UTF-8,UTF-16, ISO/IEC 8859-2 (Latin-2). find which character set used in server, and use the same character set for encoding.
if it is UTF-8 encode like this
BufferedReader bufferedReader= new BufferedReader(new InputStreamReader(inputStream), Charset.forName("UTF_8"));
if you had deffrent character set use that.
I have faced same issue because of the swedish characters.
So i have used BufferedReader to resolved this issue. I have converted the Response using StandardCharsets.ISO_8859_1 and use that response. Please find my answer as below.
BufferedReader r = new BufferedReader(new InputStreamReader(response.body().byteStream(), StandardCharsets.ISO_8859_1));
StringBuilder total = new StringBuilder();
String line;
while ((line = r.readLine()) != null)
{
total.append(line).append('\n');
}
and use this total.toString() and assigned this response to my class.
I have used Retrofit for calling web service.
I finally found this way which worked for me
InputStream input1 = new BufferedInputStream(conection.getInputStream(), 300);
BufferedReader r = new BufferedReader(new InputStreamReader(input1, "Windows-1252"));
I figured out by this windows-1252, by putting json file in asset folder of the android application folder, where it showed same special characters like specified above,there it showed auto suggestion options to change encoding to UTF-8,ISO-8859-1,ASCII and Windows-1252, So I changed to windows-1252, which worked in android studio which i replicated the same in our code, which worked.

Simplest way to download text from URL

Is there a simplest way to download small text string from URL like this one:"http://app.georeach.com/ios/version.txt"
In iOS its pretty simple. But for android em not finding something good. what is the method for getting text like that from the above URL??
I used this code in onCreate of hello app,n app crashed:
try {
// Create a URL for the desired page
URL url = new URL("http://app.georeach.com/ios/version.txt");
// Read all the text returned by the server
BufferedReader in = new BufferedReader(new InputStreamReader(url.openStream()));
String str;
StringBuilder sb = new StringBuilder(100);
while ((str = in.readLine()) != null) {
sb.append(str);
// str is one line of text; readLine() strips the newline character(s)
}
in.close();
tv.setText(sb.toString());
} catch (MalformedURLException e) {
tv.setText("mal");
} catch (IOException e) {
tv.setText("io");
}
You have to create a new class extended from AsyncTask. You can't do network stuff in the main thread. It could work but you may not want to do that. Take a look at this link : http://developer.android.com/reference/android/os/AsyncTask.html
Also don't forget to add Internet permissions to your AndroidManifest.xml.
Try this:
URL url = new URL("http://bla-bla...");
HttpURLConnection connection = (HttpURLConnection) url.openConnection();
InputStream in = connection.getInputStream();
BufferedReader br = new BufferedReader(new InputStreamReader(in));
StringBuilder sb = new StringBuilder();
String line;
while ((line = br.readLine()) != null) {
sb.append(line);
}
// your text is here
String text = sb.toString()
Do not forget to catch and handle IOException and close all streams.
An "easier" way would be this:
String url2txt = null;
try {
// Being address an URL instance
url2txt = new Scanner(address.openStream(), "UTF-8").useDelimiter("\\A").next();
} catch (IOException e) { ... }
The thing is what you consider "easier". As far as code goes, probably this is the shortest way, but it depends on what you want to do afterwards with the obtained text.

HttpUrlConnection.getInputStream returns empty stream in Android

I make a GET request to a server using HttpUrlConnection.
After connecting:
I get response code: 200
I get response message: OK
I get input stream, no exception thrown but:
in a standalone program I get the body of the response, as expected:
{"name":"my name","birthday":"01/01/1970","id":"100002215110084"}
in a android activity, the stream is empty (available() == 0), and thus I can't get
any text out.
Any hint or trail to follow? Thanks.
EDIT: here it is the code
Please note: I use import java.net.HttpURLConnection; This is the standard
http Java library. I don't want to use any other external library. In fact
I did have problems in android using the library httpclient from apache (some of their anonymous .class can't be used by the apk compiler).
Well, the code:
URLConnection theConnection;
theConnection = new URL("www.example.com?query=value").openConnection();
theConnection.setRequestProperty("Accept-Charset", "UTF-8");
HttpURLConnection httpConn = (HttpURLConnection) theConnection;
int responseCode = httpConn.getResponseCode();
String responseMessage = httpConn.getResponseMessage();
InputStream is = null;
if (responseCode >= 400) {
is = httpConn.getErrorStream();
} else {
is = httpConn.getInputStream();
}
String resp = responseCode + "\n" + responseMessage + "\n>" + Util.streamToString(is) + "<\n";
return resp;
I see:
200
OK
the body of the response
but only
200
OK
in android
Trying the code of Tomislav I've got the answer.
My function streamToString() used .available() to sense if there is any data received,
and it returns 0 in Android. Surely, I called it too soon.
If I rather use readLine():
class Util {
public static String streamToString(InputStream is) throws IOException {
StringBuilder sb = new StringBuilder();
BufferedReader rd = new BufferedReader(new InputStreamReader(is));
String line;
while ((line = rd.readLine()) != null) {
sb.append(line);
}
return sb.toString();
}
}
then, it waits for the data to arrive.
Thanks.
You can try with this code that will return response in String:
public String ReadHttpResponse(String url){
StringBuilder sb= new StringBuilder();
HttpClient client= new DefaultHttpClient();
HttpGet httpget = new HttpGet(url);
try {
HttpResponse response = client.execute(httpget);
StatusLine sl = response.getStatusLine();
int sc = sl.getStatusCode();
if (sc==200)
{
HttpEntity ent = response.getEntity();
InputStream inpst = ent.getContent();
BufferedReader rd= new BufferedReader(new InputStreamReader(inpst));
String line;
while ((line=rd.readLine())!=null)
{
sb.append(line);
}
}
else
{
Log.e("log_tag","I didn't get the response!");
}
} catch (ClientProtocolException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
return sb.toString();
}
The Stream data may not be ready, so you should check in a loop that the data in the stream is available before attempting to access it.
Once the data is ready, you should read it and store in another place like a byte array; a binary stream object is a nice choice to read data as a byte array. The reason that a byte array is a better choice is because the data may be binary data like an image file, etc.
InputStream is = httpConnection.getInputStream();
byte[] bytes = null;
ByteArrayOutputStream baos = new ByteArrayOutputStream();
byte[] temp = new byte[is.available()];
while (is.read(temp, 0, temp.length) != -1) {
baos.write(temp);
temp = new byte[is.available()];
}
bytes = baos.toByteArray();
In the above code, bytes is the response as byte array. You can convert it to string if it is text data, for example data as utf-8 encoded text:
String text = new String(bytes, Charset.forName("utf-8"));

how I get the html source with utf-8 format?

I write this code to get html source from a site.
HttpURLConnection connection;
OutputStreamWriter request = null;
URL url = null;
String response = null;
String parameters = "aranan="+et.getText();
try
{
url = new URL("http://www.fragmanfan.com/arama.asp");
connection = (HttpURLConnection) url.openConnection();
connection.setDoOutput(true);
connection.setRequestProperty("Content-Type", "application/x-www-form-urlencoded");
request = new OutputStreamWriter(connection.getOutputStream());
request.write(parameters);
request.flush();
String line = "";
InputStreamReader isr = new InputStreamReader(connection.getInputStream());
BufferedReader reader = new BufferedReader(isr);
StringBuilder sb = new StringBuilder();
while ((line = reader.readLine()) != null)
{
sb.append(line + "\n");
}
// Response from server after login process will be stored in response variable.
response = sb.toString();
// You can perform UI operations here
browser.loadDataWithBaseURL(null, response,"text/html", "UTF-8", null);
isr.close();
reader.close();
}
catch(IOException e)
{
// Error
}
}
});
But there is a one problem.It is : response (the variable that have html source) is not utf-8 format.
How I can fix this?
Thanks.
.
.
.
InputStreamReader isr = new InputStreamReader(connection.getInputStream(),"ISO-8859-9");
.
.
.
Since your response seems to be your HTML webpage in a single String, you should make sure that the head tag of your page cointains the label that defines the codification.. if not you can append it yourself to your StringBuilder.
Here is how you can do it:
final StringBuilder sb =
new StringBuilder("<html><head>"+ "<meta http-equiv=\"content-type\"content=\"text/html;charset=utf-8\" />"+ "</head><body>");
while ((line = reader.readLine()) != null) {
sb.append(line + "\n");
}
response = sb.toString();
sb.append(response);
sb.append("</body></html>");
and then you can properly load your HTML to your webview / browser. (this worked for me so I know for sure that it actually works =] )
p.d. make sure to accept the answer that properly answer your question so people keep answering your future questions.
https://meta.stackexchange.com/questions/5234/how-does-accepting-an-answer-work

Categories

Resources