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