android – Weird TagHandler behavior detecting opening and closing tags-ThrowExceptions

Exception or error:

I am trying to use TextView to display a String text with custom tags:

The String:

"<articlelink>text1</articlelink> padding<articlelink>text2</articlelink>"

Where articlelink is a custom tag. I use a customized HTML.TagHandler to handle the tags:

private class MyTagHandler implements Html.TagHandler {

    private int startIndex = 0;
    private int endIndex = 0;

    @Override
    public void handleTag(boolean opening, String tag, Editable output, XMLReader xmlReader) {
        if (tag.equals("articlelink")) {
            if (opening) {
                startIndex = output.length();
                DebugLog.d("OPEN " + startIndex);
            } else {
                endIndex = output.length();
                DebugLog.d("END " + endIndex);
                MyClickableSpan span = new MyClickableSpan();
                output.setSpan(span, startIndex, endIndex, Spanned.SPAN_EXCLUSIVE_EXCLUSIVE);
            }
        }
    }
}

However the log is:

OPEN 0
OPEN 13
END 18
END 18

However, after I insert a character before the string then the output is what I expected:

String:

"a<articlelink>text1</articlelink> padding<articlelink>text2</articlelink>"

OUTPUT:

OPEN 1
END 6
OPEN 14
END 19

What happened here? Is this a bug or I misused it?

How to solve:

I solved this problem by adding to the beginning of the string “zero width joiner”

String looks like:

"&zwj;<articlelink>text1</articlelink>padding<articlelink>text2</articlelink>"

In result textview, this symbol is not visible and text looks like the original string

###

I have also encountered this issue while writing my custom TagHandler. This seems to me like an Android bug. Even though the question is old, because there isn’t really much info on this issue out there, I will still post my solution… it may help someone.

The problematic case appears when the text starts with the HTML tag (at index 0), the callback to “handleTag()” with the closing flag will be triggered when processing reaches the end of the text.

My (kind of ugly) workaround for this problem was to use separate tags for opening and closing marks, like:

"<start>text1<end> padding<start>text2<end>"

Notice the “end” tag is not a closing one (it is not preceded by “/”).

By doing this, you will need to change your logic in the handleTag() method, with the following general form:

public void handleTag(boolean opening, String tag, Editable output, XMLReader xmlReader) {
    if (tag.equalsIgnoreCase("start")) {
        // Handle opening of your tag
    } else if (tag.equalsIgnoreCase("end")) {
        // Handle closing of your tag
    }
}

The boolean “opening” parameter is no longer needed, and also the output.length() will be correctly returned since the problem is only with the closing tag, which you won’t be using.

###

Ran into this issue as well, what seems to work is to wrap the text in <html>...</html> tags. That way the html tag will be the one that gets closed last anyway and the rest of the enclosed tags will work fine.

Leave a Reply

Your email address will not be published. Required fields are marked *