Using Eclipse 3.7.2
Android 2.3.3 / API Level 10
I am having trouble reading an XML file. I "think" I get a proper handle on the file with this code and open it for input / output as I will want to read the info, display for user, then update with any changes.
Coming from the c# world when I goto read the file I see a behavior I am unfamiliar with. In the debug perspective my variables have red square values. Now this may be OK but my first thought is red == trouble? However the data (the data in the variables window of the debug perspective) seems ok so I proceed. My eventType is a zero and I enter into the case statement but then I throw an exception. Now here I drop the ball. I don't know how to get more information about exceptions in Java. For example in the c# world I could get the inner exception. I'm sure there is a way in Java I just haven't learned yet.
Here are the steps:
From line 1 I jump straight to line 9. F6 (Eclipse debug shortcut for "Step over") takes me to line 4, F6 again back to line 9, F6 a final time and I goto my catch for a generic exception.
try
{
DataFileOut = new FileOutputStream(LiftFile);
DataFileIn = new FileInputStream(LiftFile);
InputStreamReader isr = new InputStreamReader(DataFileIn);
// auto-detect the encoding from the stream
parser.setInput(isr);
int eventType = parser.getEventType();
Category currentCategory = null;
boolean done = false;
while (eventType != XmlPullParser.END_DOCUMENT && !done)
{
String name = null;
0 //eventType = 2;
1 switch (eventType)
{
3 case XmlPullParser.START_DOCUMENT:
4 break;
case XmlPullParser.START_TAG:
....
}
9 eventType = parser.next();
}
}
So my thoughts are I have a bad FileInputStream handle or my XML document is not well formed?? Any other thoughts?
<?xml version="1.0" encoding="UTF-8"?>
<ExcersiseInformation>
<Lifts count="6">
<Lift>
<ID>1001001</ID>
<Name>Hammer Curls</Name>
<PreviousLift>45</PreviousLift>
<PreviousReps>8</PreviousReps>
<SuggestLift>45</SuggestLift>
<SuggestReps>10</SuggestReps>
<ActualLift></ActualLift>
<ActualReps></ActualReps>
</Lift>
.....
</Lifts>
</ExcersiseInformation>
Your xml seems to be well formed. Are you using a handler and parser class to get xml tag contents? Probably best method to reach it. You can find some good examples on internet or other posts. Please take a look to following one, same method that I am using successfuly
http://www.jondev.net/articles/Android_XML_SAX_Parser_Example
Related
I am facing a strange issue, and I am not able to debug it out. I have implemented a logic for uploading stream of data and am using Volley for the same, I have customized a logic little bit in HurlStack, addBodyIfExists api,so that body of type "application/octet-stream" can be handled.
My logic is to post progress to user, so that UI can be updated indicating user progress in upload, below my logic for same.
int toRead = length; // File length
byte[] data = new byte[4096];
connection.setDoOutput(true);
if(length != -1) {
connection.setFixedLengthStreamingMode(length);
} else {
connection.setChunkedStreamingMode(4096);
}
OutputStream os;
int i;
int count;
os = connection.getOutputStream();
int progress= 0;
try {
for(i = 0; (count= is.read(data)) > 0; ++i) { // is, is not null and contains a valid input stream
os.write(data, 0, count); // at this line am getting unexpected end of stream
progress+= count;
if(i % 20 == 0) {
rs.deliverProgress(progress, 0L);
progress= 0;
}
}
os.flush();
} finally {
if(is != null) {
is.close();
}
if(os != null) {
os.close();
}
}
on executing above code am getting this, although I have verified, output stream is not null, neither do input stream, it fails in first iteration of read loop itself, am seeing it has read 4096 bytes and then trying to write the same.
java.net.ProtocolException: unexpected end of stream
at com.android.okhttp.internal.http.HttpConnection$FixedLengthSink.close(HttpConnection.java:326)
at com.android.okio.RealBufferedSink.close(RealBufferedSink.java:174)
at com.android.okio.RealBufferedSink$1.close(RealBufferedSink.java:142)
any help in debugging above will he highly appreciated.
This may help you :
That exception is thrown by FixedLengthInputStream when the expected number of bytes (usually set in the content-length header of the response) is larger than the actual data in the response.
Check that the content-length header is correct. (If you're supplying your own value for the content length, make sure it is correct.)
It would help to see your code that sets up the input stream.
Already Fixed it, please add "Accept-Encoding", "identity" in header, then the server-side will get command that it will not modify the response, then send back to Clients.
If you have checked everywhere in your code and tried every solution in stackoverflow and github but the issue still occurs, and you have only tested your code on emulator, then, you should try to run your code on your real device instead. Maybe it will work, or maybe it won't, but if you feel desperate, just have a try, seriously. I was astonished when I happened to find that my code ran with bugs on emulator everytime but successfully on my mobile phone. Besides, the code also ran sucessfully on others' android emulators. So I guess there is something wrong in my android studio configuration that I can't find out. I have no idea why this happen, just like we don't know why "Clean Project/Invalidate caches" sometimes works better than any solution.
It is a little strange that your data length might be unknown.
Is it a media file? Or a live stream?
Anyway, I tried to upload my live stream data. And it happened in the same error.
I added this setting to the Connection and solved my problem.
Transfer-Encoding : chunked
("setChunkedStreamingMode" didn't work. I still don't know why.)
This happens for me on android emulator and doesn't happen on my physical android device.
I was doing GET request to flask server running on 0.0.0.0 on my laptop from the android app.
To fix it on the emulator, add the servers ip address in the emulators proxy.
see How to set up Android emulator proxy settings
The exact problem i had was unexpected end of stream retrofit
I'm using JDOM with my Android project, and every time I get a certain set of characters in my server response, I end up with these error messages:
05-04 10:08:46.277: E/PARSE: org.jdom.input.JDOMParseException: Error on line 95 of document UTF-8: At line 95, column 5263: unclosed token
05-04 10:08:46.277: E/Error Handler: Handler failed: org.jdom.input.JDOMParseException: Error on line 1: At line 1, column 0: syntax error
When I make the same query through google chrome, I can see that all of the XML came through fine, and that there are in fact no areas where a token is not closed. I have run into this problem several times throughout the development of the application, and the solution has always been to remove odd ascii characters (copyright logos, or trademark characters, etc. that got copied/pasted into those data fields). How can I get it to either a remove those characters, or b strip them and continue the function. Here's an example of one of my parse functions.
public static boolean parseUserData(BufferedReader br) {
SAXBuilder builder = new SAXBuilder();
Document document = null;
try {
document = builder.build(br);
/* XML Output to Logcat */
if (document != null) {
XMLOutputter outputter = new XMLOutputter(
Format.getPrettyFormat());
String xmlString = outputter.outputString(document);
Log.e("XML", xmlString);
}
Element rootNode = document.getRootElement();
if (!rootNode.getChildren().isEmpty()) {
// Do stuff
return true;
}
} catch (Exception e) {
GlobalsUtil.errorUtil
.setErrorMessage("Error Parsing XML: User Data");
Log.e(DEBUG_TAG, e.toString());
return false;
}
}
It distinctly sounds like a character encoding issue. I think duffymo is correct in his assessment. I have two comments though ....
If you are getting your data through a URL you should be using the URLConnection.getContentType() to get the charset (if it is set and the charset is not null) to set up the InputStreamReader on the URL's InputStream...
Have you tried JDOM 2.0.1? It is the first JDOM version that is fully tested on Android... (and the only 'supported' JDOM version on Android). JDOM 2.0.1 also has a number of performance tweaks, and memory optimizations that should make your processing faster. It also fixes a number of bugs.... though from what I see you should not run in to any bug problems.....
Check out https://github.com/hunterhacker/jdom/wiki/JDOM2-Migration-Issues and https://github.com/hunterhacker/jdom/wiki/JDOM2-and-Android
Is the BufferedReader constructed to take the encoding argument? Perhaps you need to tell the Reader or InputStream that you pass to use UTF-8.
Question on the Sax XML parser on Android, using Java: I need to parse XML files I get from the web, and that I have no control over. Some contain errors and cause the parser to abort with errors like "mismatched tag" or "not well-formed (invalid token)".
Those errors don't matter to me, I want to ignore them and keep going, I can handle the broken XML structure. But I cannot fix the XML files, they are not mine. How can I tell Sax on Android (class org.xml.sax.XMLReader) to not throw an exception and keep going? Attaching an ErrorHandler didn't work, and catching the exception is of no use because I can't resume parsing where it stopped.
My XML is not HTML, but here are some (X)HTML examples where browsers ignore errors and keep going. I want to do this too.
Browsers are fine with "<br>" instead of "<br/>" even though the tag is never closed.
"<b><i> text </b></i>" works even though the closing tags are in the wrong order.
"odds & ends" is accepted despite the invalid token, "odds & ends" would be correct.
I'd prefer to not write my own parser, dealing with character set conversions and all that. I don't need to validate XML. Here's my code, reduced to the essentials:
XMLReader r = SAXParserFactory.newInstance().newSAXParser().getXMLReader();
r.setErrorHandler(new MyLenientErrorHandlerThatNeverThrows());
r.setContentHandler(new MyImporterThatExtendsDefaultHandler());
r.parse(new InputSource(new BufferedReader(...)));
Thanks!
Ok, it appears it can't be done. Sax supports error detection but not error recovery, which makes it less than ideal for robust code in this example.
Got it to work by replaxing Sax with XmlPullParser, which allows wrapping the next-token call in a try-catch block:
try {
XmlPullParserFactory factory = XmlPullParserFactory.newInstance();
XmlPullParser xpp = factory.newPullParser();
xpp.setInput(in);
int type = xpp.getEventType();
while (type != XmlPullParser.END_DOCUMENT) {
switch (type) {
case XmlPullParser.START_TAG: startTag(xpp); break;
case XmlPullParser.END_TAG: endTag(xpp); break;
case XmlPullParser.TEXT: characters(xpp.getText()); break;
}
try {type = xpp.next();}
catch (XmlPullParserException e) {}
}
} catch (Exception e) {}
I want to achieve the following but so far, no luck
Open a file in the SD Card when the android application first started.
Stream the logcat output to the file.
When the application exits, stop the logcat streaming.
In my ApplicationClass extends Application onCreate() method, I do this
wwLogManager.openLogFile();
and here's the code in the openLogFile()
private static final String LOGCAT_COMMAND = "logcat -v time -f ";
String timestamp = Long.toString(System.currentTimeMillis());
String logFileName = BuildConstants.LOG_LOCATION + "_" + timestamp + ".log";
mLogFile = new File(Environment.getExternalStorageDirectory() + logFileName);
mLogFile.createNewFile();
String cmd = LOGCAT_COMMAND + mLogFile.getAbsolutePath();
Runtime.getRuntime().exec(cmd);
I do get log files in the sd card, but the log output in these files do not have any trace of the Log.i() calls that I placed in my activities. Is the logcat command that I used here correct? Thanks!
I apologize if I am misunderstanding your goals, but perhaps you could use the java.util.logging API instead of using Logcat or the Android Logging mechanism.
Like the Android logging API, the java.util.logging API allows you to easily log messages at various levels, such as FINE, FINER, WARN, SEVERE, etc.
But the standard logging API has additional advantages, too. For example, you can easily create a log file by using a FileHandler. In fact, FileHandler has a built-in log rotation mechanism, so you don't have to worry (so much) about cleaning up the log files. You can also create a hierarchy of Loggers; so, for example, if you have two Loggers, com.example.foo and com.example.foo.bar, changing the logging level of the former will also change the logging level of the latter. This will even work if the two Loggers are created in different classes! Moreover, you change logging behavior at runtime by specifying a logging configuration file. Finally, you can customize the format of the log by implementing your own Formatter (or just use the SimpleFormatter to avoid the default XML format).
To use the standard logging API, you might try something like this:
// Logger logger is an instance variable
// FileHandler logHandler is an instance variable
try {
String logDirectory =
Environment.getExternalStorageDirectory() + "/log_directory";
// the %g is the number of the current log in the rotation
String logFileName = logDirectory + "/logfile_base_name_%g.log";
// ...
// make sure that the log directory exists, or the next command will fail
//
// create a log file at the specified location that is capped 100kB. Keep up to 5 logs.
logHandler = new FileHandler(logFileName, 100 * 1024, 5);
// use a text-based format instead of the default XML-based format
logHandler.setFormatter(new SimpleFormatter());
// get the actual Logger
logger = Logger.getLogger("com.example.foo");
// Log to the file by associating the FileHandler with the log
logger.addHandler(logHandler);
}
catch (IOException ioe) {
// do something wise
}
// examples of using the logger
logger.finest("This message is only logged at the finest level (lowest/most-verbose level)");
logger.config("This is an config-level message (middle level)");
logger.severe("This is a severe-level message (highest/least-verbose level)");
The Android logging mechanism is certainly easy and convenient. It isn't very customizable, though, and log filtering must be done with tags, which can easily become unwieldy. By using the java.uitl.logging API, you can avoid dealing with a multitude of tags, yet easily limit the log file to specific parts of your application, gain greater control over the location and appearance of the log, and even customize logging behavior at runtime.
I repost my answer here so #JPM and others can see... The code basically just execute the logcat command and then build the log from the input stream.
final StringBuilder log = new StringBuilder();
try {
ArrayList<String> commandLine = new ArrayList<String>();
commandLine.add("logcat");
commandLine.add("-d");
ArrayList<String> arguments = ((params != null) && (params.length > 0)) ? params[0] : null;
if (null != arguments){
commandLine.addAll(arguments);
}
Process process = Runtime.getRuntime().exec(commandLine.toArray(new String[0]));
BufferedReader bufferedReader = new BufferedReader(new InputStreamReader(process.getInputStream()));
String line;
while ((line = bufferedReader.readLine()) != null){
log.append(line);
log.append(LINE_SEPARATOR);
}
}
catch (IOException e){
//
}
return log;
Try manually setting a filter as described here:
http://developer.android.com/guide/developing/debugging/debugging-log.html#filteringOutput
Something like:
logcat ActivityManager:I MyApp:V *:S
If you replace "MyApp" with the log tags that you are using, that should show you all info (and greater) logs from ActivityManager, and all verbose (and greater) logs from your app.
I know this is a late answer to the question but I would highly recommend using Logback to write messages to a log file as well as the logcat.
Copy logback-android-1.0.10-2.jar and slf4j-api-1.7.5.jar to your libs folder.
Right-Click on both libs and from the menu select Build Path -> Add to Build Path.
Create a logback.xml file in your assets folder and enter the following:
%msg
WARN
${LOG_DIR}/log.txt
%d{HH:mm:ss.SSS} [%thread] %-5level %logger{36} - %msg%n
To write a log:
public class MyActivity extends Activity
{
public static final Logger logger = LoggerFactory.getLogger(MyActivity.class);
protected void onCreate(Bundle b)
{
super(b);
try{
throw new Exception("Test");
}catch(Exception e){
logger.error("Something bad happened",e);
}
}
}
I have a curious problem, respectively a weird effect of using my self-programmed android App.
My app reads out the HTML-source-code of a website and parse it for my desired information. And it work... oh well, not really consistent.
Scenario 1: I use my WLan at home and run my app -> All is working fine. All desired items can be seen in my ListView
Scenario 2: I use my mobile Internet, like Edge or HSDPA -> My ListView is only presenting 1 Item. All of the others are vanished...
I don' t know why. Could there be any time-out, that detain the app to read out the whole HTML-site? But all of the other items would directly follow in the next line of the HTML-source-code...
I have no idea how could I fix it. On google I didn' t find anyone else with the same problem.
Regards, Julian
Here is some code
// With this I get the HTML-source-code
URL url = new URL("http://www.area4.de);
URLConnection conn = url.openConnection();
DataInputStream dataIn = new DataInputStream(conn.getInputStream());
BufferedReader reader = new BufferedReader(new InputStreamReader(dataIn, "UTF-8"));
String line;
// Then I parse the code with
while ((line=reader.readLine()) != null)
{
if (line.contains(searchPattern))
al.add(line); //al is an ArrayList
}
That was all I do in my app till now (besides presenting the arrayList in a ListView).
The source code of the site you can see in your browser (Ctrl + u). I search for these lines
THIRTY SECONDS TO MARS //
DROPKICK MURPHYS //
With 3G I only get thirty-seconds-to-mars...
Ah, I solved it. I searched, as it can be seen above, with this code-snippet
while ((line=reader.readLine()) != null)
{
if (line.contains(searchPattern))
al.add(line); //al is an ArrayList
}
With WLan (and my emulator) I really have a new line for each band e. g.:
line1
line2
line3
....
But with Edge or HDSPA all lines I get with Wlan are written in one line.
line1line2line3.... And with my regex i delte all before and after the line when I find a desired target. Hope you understand, it' s difficult to explain it in a foreign language.
A simple
while (line.contains(searchPattern))
fixed it.
You can always try reading whole http response before sending it for parsing. This way you get to see whole document is loaded properly.