Android XmlPullParser whitespace hack. How would I do this more elegantly? - android

I have some XML in an Android application where XmlPullParser is the recommended solution for binding that XML to data model classes. The Android documentation for XmlPullParser is fairly good except for how to deal with inter element whitespace. The recommended approach is to detect low-level IGNORABLE_WHITESPACE parsing events and skip over those events. However for the XML I am trying to accept, this approach is not working for me. I never see the low level IGNORABLE_WHITESPACE events occurring. Which has me believing that I do not correctly understand some aspect of my particular use case, either XmlPullParser behavior, acceptable XML, or possibly a configuration issue.
My simplified test case for an XML snippet that I am trying to accept is:
<a> <b></b> </a>
and the code hack I am using to accept this element with the recommended getNextToken() method is:
boolean hasEvent = false;
String desc = null;
while (!hasEvent) {
result = xpp.nextToken();
desc = xpp.getPositionDescription();
Log.i(TAG, String.format("Processing: %s", desc));
switch (result) {
case START_TAG:
case END_TAG:
case END_DOCUMENT:
hasEvent = true;
break;
case TEXT:
// Use a real hack to detect whitespace.
if (desc.contains("TEXT (whitespace)#")) {
hasEvent = false;
} else {
hasEvent = true;
}
break;
default:
break;
}
}
and the result that I see is, essentially: got START_TAG(a), got TEXT (whitespace), got START_TAG(b), got END_TAG(b), got TEXT (whitespace), got END_TAG(a).
So the questions are: what am I not understanding correctly? And how would I accept this sequence without resorting to an ugly hack, something more in keeping with recommended use of XmlPullParser.
I have a hunch that this is questionable XML but it is representative of what I will be presented with, i.e. I cannot control the inter-element whitespace in the input stream.
fwiw, the Simple Framework for XML deals with this input stream without a hiccup and is my preferred approach but that package is very, very messy to use with Gradle and Android Studio due to dependency conflicts with the underlying stax and epp libraries, but that is another issue entirely.

To somewhat answer my own question, I offer up the following for developers who find themselves in my situation at some point. But I very much look forward to even better answers soon.
As for lack of understanding, the first point is that now I understand that I am using a non validating parser. This claim is made in the Android XmlPullParser source code/Javadoc for isWhitespace():
Please note: non-validating parsers are not able to distinguish whitespace and ignorable whitespace, except from whitespace outside the root element. Ignorable whitespace is reported as separate event, which is exposed via nextToken only.
This leads me to believe that JAXB and Simple are validating parsers and can deal with this inter-element whitespace in stride whereas I now must deal with it explicitly, much to my chagrin.
A second point that falls under the lack of understanding umbrella is that Android's XmlPullParser can only create validating parsers by providing a "schema" to back the validation, something that is pretty much out of my control for this instance.
As for a more elegant way to deal with inter-element whitespace, my answer would be to have two methods: getNextElement() which will return the next START_TAG or END_TAG event but throw away all TEXT events where the text is whitespace, anything else is deemed a parsing error; the other method would be getNextText() which will return text from either TEXT or CDSECT parsing events and report any other event as an error.
As I said, I'm looking forward to better answers.

Related

Does Kotlin code gets "minified" when compiled?

In Typescript (or JavaScript) I always try to write in a way that if I (or another developer) has to touch my code in one year, it is really easy to understand what is happening. So I do not try to find the shortest code possible but the clearer one.
I do not worry about the size of the file because I know in production this function:
function myFunction(value: number) {
if(otherFunction(number){
return true;
}
if(yetAtherFunction(number){
return true;
}
return false;
}
will be converted to this:
function myFunction(n){return!!otherFunction(n)||!!yetAtherFunction(n)}
Would something similar happens with kotlin?
I ask because I offen find this kind of code:
val myDrawable = item?.image?.let { Uri.parse(it.toString()) } ?: R.drawable.my_default_image
and to me it is not easy to do a fast parse to know what is happening why doing a PR or similar.
If I write that in a more verbose way, would it have an impact on the size of the final apk ?
Important:
To clarify, I am not asking is it better to write in this or that way? I am asking if the compiler tries to optimize the input like a typescript/javascript minifier does.
In Kotlin / Java world, all code must get compiled into bytecode before it can run anywhere, and in general this is basically an incredibly optimized binary blob where whitespace doesn't exist.
In interpreted languages like JS, the client / browser downloads a copy of the source and runs the source directly. Minifying is super important in these cases because it reduces the size of the file clients need to download by removing logically redundant characters. In TS, most clients cannot run it directly, so it instead gets transpiled into JS, and that is what is typically served to browsers / clients. (Some exceptions like Deno exist for example, which has a native ts interpreter).
The reason you see inlined code stuffed into one line, is purely for cosmetic / code style purposes.
Additional whitespace and variable names generally have no impact on the size / performance of your compiled Android app, so you can simply write code in the way that seems most presentable to you.

Android Data-Binding : Example vs Reality

In all the data-binding examples that shows Generic data type handling developer.android.com uses real char < and >.
but when it comes to reality
I am getting below error.
The value of attribute "type" associated with an element type
"variable" must not contain the '<' character.
I've searched the web and found people use > for > and < for < as a fix.
Questions
Is this supposed to happen ? If yes why it's not mentioned in the docs ?
Is there any fix for this, where I can write the layout as given in the official docs? (without using corresponding html entity characters)
There's unlikely to be a change to this because layout files are still XML, this isn't really the fault of Android or DataBinding, you're going to need to use appropriate encoding for HTML entities within an XML document.
Using < isn't that terrible as a fix, as far as resolutions go, but if you'd rather avoid using it, then it may be an option to simplify your binding expressions to move logic away from the layout and into your variables.
The current advised method of doing so is with a ViewModel, which can be bound to the layout and expose observable LiveData values.
I can't give you a reason for it not being in the documentation besides that it's probably just not advised to do so.
Now they've updated the documentation

How to allow hard coded strings and stop asking about using strings.xml

I'm working currently on an android project and I have no plans in mind whatsoever to translate it to other languages, so I'm not saving string literals in strings.xml. However Android Studio keeps complaining everytime I hard code a string literal especially when setting the text value for a TextView.
Is there a way to disable these warnings?
you can edit it in the following location Settings->Editor->Inspections->Android Lint->TextView Internationalization:
and for the xml Settings->Editor->Inspections->Android Lint->Hardcoded Text:
The best way to do this in my opinion is to use a gradle file, this will allow you to suppress these globally without having to do it in Android Studio, so your settings can go into source control as well, and then you don't have to individually decorate each method you want to apply the warning to. To do this, disable SetTextI18n in your gradle files lint options as follows:
android {
lintOptions{
disable 'SetTextI18n'
}
}
Gradle sync and voila, warnings gone.
Add
#SuppressLint("SetTextI18n")
on top of your function(s).
Example:
#SuppressLint("SetTextI18n")
private void updateEZWBMode2ConnectionStatus(){
switch (IsConnected.checkMode2(mContext)){
case IsConnected.USB_TETHERING:
M2StatusTV.setText("Status: Connected");
M2StatusTV.setTextColor(Color.argb(255,0,255,0));
M2ReceiveTV.setVisibility(View.VISIBLE);
startTestReceiverSafe(M2ReceiveTV);
break;
case IsConnected.USB_CONNECTED:
M2StatusTV.setText("Status: No Tethering");
M2StatusTV.setTextColor(Color.argb(255,255,51,51));
M1ReceiveTV.setVisibility(View.GONE);
M2ReceiveTV.setVisibility(View.GONE);
stopTestReceiverSafe();
break;
case IsConnected.USB_NOTHING:
M2StatusTV.setText("Status: No USB Connection");
M2StatusTV.setTextColor(Color.argb(255,255,51,51));
M1ReceiveTV.setVisibility(View.GONE);
M2ReceiveTV.setVisibility(View.GONE);
stopTestReceiverSafe();
break;
}
}
Old question, but anyway the accepted answer is misleading.
There is no need to translate string literal resources. In fact, they can be marked as non-translatable in the resources file. This way, you'll still adhere to best practices while not being annoyed by lint and translations.
<string name="invite_sent" translatable="false">Invite sent</string>
While disabling Lint my be useful to stop being annoyed, there is a further reason you want to (and should) use string literal resources: repetition. Following the DRY (Don't Repeat Yourself) principle can avoid a miriad of problems down the line, from complex refactors to unexpected behaviour, as well as inconsistency in the user(s) experience while using the app. Just imagine that an "Ok" button is present in 10+ screens. Having a single reference and source simplifies and centralizes maintenance of the project.

How to get value between tags with sax contenthandler?

I'm parsing some XML with a ContentHandler, and I can get attributes within tags fine, but I don't see how to get the actual values. For example, take this simple xml:
<code>
< thing id="12345" key="abcde" >
< description > Some text is here < /description >
< otherdata > I don't actually care about or want this text < /otherdata >
< /thing >
</code>
(Apologies for the formatting there...)
So, in my StartElement() I can get the id and key values fine with att.getValue("id") for example. But how do I get the text between the description tags?
Based on reading the docs it look like I need to use the characters() method, but this will presumably occur for all other tags in the xml (the real example is more complex than the above, and I don't need all of it) - how do I relate the character array back to a specific tag? All it gives me is a start and a length but from that I don't know which element it relates to.
I'm obviously missing something obvious here but none of the docs or examples I find seem to help - most examples just show the whole doc being squirted out to a console, which is fine but doesn't help with my scenario.
You can put Flag value whenever you parse description inside the startElement(), and make it false inside the endElement(). In between this, you can have value of description inside the characters() method.
use
_data.sectionId = atts.getValue("id");
refer this link for detailed example
http://www.jondev.net/articles/Android_XML_SAX_Parser_Example
SAX is a very low-level API for parsing, and the price you pay for this is that you have to manage context and state within your application code. Nearly all SAX applications will maintain a stack of element names, so that when text arrives, you know what element it belongs to by peek()ing at the stack.
SAX seems to be becoming very popular on Android, and I'm not sure whether that's because there's nothing else available or because the efficiency is needed. But the fact is, SAX is a very difficult interface to program to, and for high performance you pay a heavy price in usability.

How to perform Redo Undo operation in EditText

I want to know is there any method or any link or tutorial to perform redo undo operation in Android edittext. If any one knows than please let me know.
Quick note on the Antti-Brax/Divers(Kidinov) solution. It works great, except if you try to use it with a TextView post-API 23, you'll run into problems, because guess-what, Google actually added a hidden UndoManager (android.content.UndoManager) and didn't document it or make it obvious it was there. But if you have a hard/bluetooth keyboard in Marshmallow or Nougat and hit ^Z or SHIFT-^Z, you'll get undo/redo.
The problem comes if you're already using Antti-Brax's class with an EditText, and you also hook it to ^Z and shift-^Z, you'll run into problems with anyone using a hard keyboard. Namely the ^Z will trigger BOTH the native and Antti-Brax's undo, leading to two undos simultaneously, which isn't good. And after a few of them, you'll probably get a Spannable out of bounds crash.
A possible solution I found is to subclass the TextView/TextEdit/whatever and intercept the undo/redo calls from the TextView so they don't run as follows:
#Override
public boolean onTextContextMenuItem(int id) {
int ID_UNDO, ID_REDO;
try {
ID_UNDO = android.R.id.undo;
ID_REDO = android.R.id.redo;
} catch (Resources.NotFoundException e) {
ID_UNDO = 16908338; // 0x1020032
ID_REDO = 16908339; // 0x1020033
}
return !((id == ID_UNDO) || (id == ID_REDO)) && super.onTextContextMenuItem(id);
}
Those magic id numbers were found here, and are used only as a backup if the android.R.id.undo values aren't found. (it also might be reasonable to assume that if the values aren't there the feature isn't there, but anyway...)
This is not the best solution because both undo trackers are still there and both are running in the background. But at least you won't trigger both of them simultaneously with ^Z. It's the best I could think to do until this gets officially documented and the getUndoManager() methods of TextView is no longer hidden...
Why they made a feature you can't turn off (or even know if it was there or not) "live" in released Android I can't say.
I just opened an issue on Android's issue tracker if anyone wants to follow this.
There is an implementation of undo/redo for Android EditText in
http://credentiality-android-scripting.googlecode.com/hg/android/ScriptingLayerForAndroid/src/com/googlecode/android_scripting/activity/ScriptEditor.java
The code works but does not handle configuration changes properly. I am working on a fix and will post here when it is complete.
My Google search was :-
android edittext onTextChanged undo
I know this is an old question, but as there is no accepted answer, and this is an issue I've tackled myself from many angles, I'd like to add my solution in case it helps anyone. My answer is probably most relevant to large (1,000words+) volumes of text editing apps that require this feature.
The simplest way to resolve this problem is to make periodic copies of all text on screen, save it to an array and call setText() every time the Undo method is called. This makes for a reliable system, but it isn't ideal for large (i.e. 1,000words+) text editing apps. This is because it:
Is wasteful. It could be that only one word changes in a two thousand word document, so that's one thousand, nine hundred and ninety nine words needlessly committed to memory.
Can lead to performance issues, as some low-tier hardware struggles with rendering large amounts of text. On some of my test devices, this method can lead to freezes of a few seconds whenever Undo is called.
The solution I currently use is comparatively complex, but I've published the results in a library here.
Essentially, this library saves a copy of text as soon as a user begins typing, and then another copy of text once they've stopped typing for a set amount of time (in my case, two seconds). The two text strings are then compared, and the altered section of text returned, the indexes where the alterations occured, and details on whether or not the change was an addition of new text, a deletion, or a replacement of old text with new text.
The net result is that only the necessary text is saved, and when Undo is called, there is only a local delete(), replace() or insert() call, which makes for much faster operations on large text fields.
Here is the undo/redo implementation that was linked to from Gary Phillips' answer extracted into a reusable and universal undo/redo plugin for any widget that descends from a TextView. I added some code for persisting the undo history.
http://code.google.com/p/android/issues/detail?id=6458#c123
Hope this helps.
To preserve EditText Styling with regards to undo:
You can create an ArrayList<EditText> or ArrayList<String> (String containing html text) to store your last 10 (for example) actions. So ArrayList [0] would contain html text from your first action and ArrayList [9] would contain html text from your very last action. Each time the user taps "undo" in your app, you would apply ArrayList [size()-1] to your EditText and then remove ArrayList [size()-1] from your Array.

Categories

Resources