I am working on an Activity in which I parse a text with markup characters. What I'm doing is converting them to several types of ClickableSpans.
The problem is that I need to implement a function (lets call it function B) that implies having overlapping ClickableSpans and that causes several issues.
So what I'm doing now is creating a new SSB while detecting the overlapping spans, and removing the ones I don't need for this particular function. Working fine.
BUT, I need to be able to go back to the previous SSB and that doesn't seem to work.
STEP BY STEP:
// I CREATE THE SSBs
...
static SpannableStringBuilder ssb;
static SpannableStringBuilder ssbCopy;
// I IMPLEMENT MY CUSTOM FUNCTION THAT PARSES THE TEXT AND SETS THE SBB AS A TEXTVIEW CONTENT
...
textView.setMovementMethod(new LinkTouchMovementMethod());
ssb = addClickablePart(chapterTextStr, markupCharactersArray);
textView.setText(ssb);
// WHEN A BUTTON IS CLICKED I IMPLEMENT MY FUNCTION B. WHERE I CREATE A COPY OF MY ORIGINAL SSB AND STORE IT IN ssbCopy, AND SET IT AS THE TEXTVIEW CONTENT
...
ssbCopy = SpannableStringBuilder.valueOf(ssb);
// I REMOVE THE OVERLAPPING SPANS
...
overlapSpans = ssbCopy.getSpans(index, index+word.length(), TouchableSpan.class);
for (int c=0;c<overlapSpans.length;c++) {
ssbCopy.removeSpan(overlapSpans[c]);
}
// I SET THE NEW CLICKABLE SPANS
...
ssbCopy.setSpan(touchableSpan, index, index + word.length(), 0);
// AND SET THE NEW SSB CONTENT TO THE TEXTVIEW
textView.setText(ssbCopy);
// EVERYTHING WORKS FINE UP TO HERE
// BUT WHEN I TRY TO SET BACK THE ORIGINAL SSB BACK AS THE CONTENT OF MY TEXTVIEW WHEN THE USER CLICKS A BUTTON
...
textView.setText(ssb);
// THE ORIGINAL SSB IS EXACTLY LIKE THE COPY (ssbCopy) AND CONTAINS THE SAME CLICKABLE SPANS I ADDED. NOT ONLY THE ORIGINAL ONES
I guess it may sound somewhat confusing and I'm not sure if I explained properly, but I can't get around this.
EDIT:
As per kcoppock answer, I learn it isn't possible to clone an ssb and valueOf(ssb) is just a copy of the object. So I ended up cloning my "ssb" manually by looping through all elements and applying them to the new ssb. Like this:
TouchableSpan[] spans = ssb.getSpans(0, ssb.length(), TouchableSpan.class);
ssbCopy = new SpannableStringBuilder(chapterTextStr+"dsadsa");
for (int c=0;c<spans.length;c++) {
TouchableSpan obj = spans[c];
ssbCopy.setSpan(obj, ssb.getSpanStart(obj), ssb.getSpanEnd(obj), 0);
}
By the way, TouchableSpan is a custom class I created that extends ClickableSpan
The problem here is your use of valueOf(). It doesn't do what you think it does. All it does is return the object passed in, if it is a SpannableStringBuilder; otherwise, it wraps the given CharSequence in a SpannableStringBuilder. From the source:
public static SpannableStringBuilder valueOf(CharSequence source) {
if (source instanceof SpannableStringBuilder) {
return (SpannableStringBuilder) source;
} else {
return new SpannableStringBuilder(source);
}
}
So essentially:
ssb == SpannableStringBuilder.valueOf(ssb);
They are one and the same Object. SpannableStringBuilder does not implement Cloneable, so there's no easy way to make a copy, other than to just generate two copies, for example:
ssb = addClickablePart(chapterTextStr, markupCharactersArray);
ssbCopy = addClickablePart(chapterTextStr, markupCharactersArray);
The method subsequence in SpannableStringBuilder copies the spans. You could make a copy of you ssb by calling ssb.subsequence(0, ssb.length)
SpannableStringBuilder ssbCopy = (SpannableStringBuilder)ssb.subSequence(0, ssb.length());
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With