8

By simply setting a TextViews text to a string defined in code (that never can be null) I sometimes get an ArrayIndexOutOfBoundsException, this only happens in my live app, I never had this issue on any test device yet... And it seems to happen sometimes only, the user tells me it happens once and the next time everything works again. Any ideas what could be the cause here? For me, it looks like this crash should never ever happen...

Code

I do following:

fun updateFilterInfo(showing: Int, total: Int) {
    binding?.tvFilterLvl1?.text = "$showing / $total" // <= THIS line creates the crash
}

Crash

And I get following crash every now and then (very rarely):

java.lang.ArrayIndexOutOfBoundsException: length=1; index=1
at android.text.SpannableStringBuilder.getSpansRec(SpannableStringBuilder.java:973)
at android.text.SpannableStringBuilder.getSpans(SpannableStringBuilder.java:866)
at android.text.SpannableStringBuilder.getSpans(SpannableStringBuilder.java:836)
at android.text.SpannableStringBuilder.sendSpanAdded(SpannableStringBuilder.java:1268)
at android.text.SpannableStringBuilder.setSpan(SpannableStringBuilder.java:773)
at android.text.SpannableStringBuilder.setSpan(SpannableStringBuilder.java:672)
at android.widget.TextView.setText(TextView.java:5981)
at android.widget.TextView.setText(TextView.java:5849)
at android.widget.TextView.setText(TextView.java:5806)
... above line of my code ...

Versions/Background

I'm using android x, newest stable versions and have this problem... Also I use kotlin 1.3.21 and Gradle plugin 3.3.2 - all this are stable and mostly the newest versions. Additionally I made sure the user does not use a custom ROM, so it can't be this either.

XML/Theme

The affected view is very simple, like the following:

<TextView
    android:id="@+id/tvFilterLvl1"
    android:layout_width="match_parent"
    android:layout_height="wrap_content"
    android:gravity="right"
    android:padding="4dp" />

No custom styling here, no custom fonts inside my project (although a system-wide custom font can never be excluded). My base app theme does not define a custom TextView style and extends Theme.MaterialComponents.Light.DarkActionBar.Bridge. So neither the XML nor the theme has any special TextView handling...

Edit 1 - I extracted the value to a local variable

fun updateFilterInfo(showing: Int, total: Int) {
    val text = "$showing / $total"
    binding?.tvFilterLvl1?.text = text
}

Still I got a crash like following:

java.lang.NullPointerException: Attempt to invoke interface method 'void android.text.SpanWatcher.onSpanAdded(android.text.Spannable, java.lang.Object, int, int)' on a null object reference
    at android.text.SpannableStringBuilder.sendSpanAdded(SpannableStringBuilder.java:1228)
    at android.text.SpannableStringBuilder.setSpan(SpannableStringBuilder.java:767)
    at android.text.SpannableStringBuilder.setSpan(SpannableStringBuilder.java:677)
    at android.text.DynamicLayout.<init>(DynamicLayout.java:187)
    at android.widget.TextView.makeSingleLayout(TextView.java:6907)
    at android.widget.TextView.makeNewLayout(TextView.java:6805)
    at android.widget.TextView.checkForRelayout(TextView.java:7341)
    at android.widget.TextView.setText(TextView.java:4482)
    at android.widget.TextView.setText(TextView.java:4339)
    at android.widget.TextView.setText(TextView.java:4314)
    .... the line above: binding?.tvFilterLvl1?.text = text
prom85
  • 16,896
  • 17
  • 122
  • 242
  • Maybe at some scenario you get null for showing or total. Test it with passing nulls and maybe try to secure it like $showing ?: 0 / $total ?: 0 – P.Juni May 18 '19 at 19:07
  • function parameters are all ready null save, a kotlin error would be thrown if you pass a null value to the function (like "passed null value for non null parameter", don't know the exect phrase currently), so this can't be the case – prom85 May 18 '19 at 19:08
  • Hmmm maybe add a log with displaying this vars before setting text and try to reproduce the error and then see if those vars are valid while error happens – P.Juni May 18 '19 at 19:11
  • I just had a quick look at the source, TextView 5806 is captured in a "shouldElipse" if statement https://android.googlesource.com/platform/frameworks/base/+/jb-release/core/java/android/widget/TextView.java#5806 (but granted this changes per platform release). Are you expecting long text? Something for you to investigate – Blundell Jun 12 '19 at 12:47
  • If you pass a String instead of the kotlin inline, does it affect the outcome? The SpannableStringBuilder is being used internally by TextView so either Kotlin is doing something strange or there's more than meet the eye. – Martin Marconcini Jun 12 '19 at 13:00
  • You're also using DataBinding, aren't you? You should mention this because I've *never* seen said crash and I use mostly the same tools/versions (Except data binding, I don't like/use it). – Martin Marconcini Jun 12 '19 at 13:01
  • 1
    updateFilterInfo() is not actually causing the crash but you are applying some span properties like underline etc, thats causing the issue, can you paste that code please? – Abdul Aziz Jun 13 '19 at 05:18
  • Reminded me of [old bugs](https://issuetracker.google.com/issues/36950033) where some combination of `ellipsize` and `lines` attributes could cause `ArrayIndexOutOfBoundsException` – bwt Jun 13 '19 at 10:27
  • @Blundell thanks for the hint, I'll check if another ellipsis option does help - I do not expect long texts, maximum numbers should be <= 10^5 – prom85 Jun 13 '19 at 10:56
  • 1
    @MartinMarconcini I have changed this and created a local string and use this now instead of directly setting the text to the kotlin inline function, currently waiting if I still get this crash – prom85 Jun 13 '19 at 10:58
  • @AbdulAziz `updateFilterInfo` is causing this crash, indirectly, the stacktrace proves it. `TextView` internally creates a spannable, this does not come from my side. – prom85 Jun 13 '19 at 11:00
  • @prom85, can you share the declaration of `tvFilterLvl1` in xml? – azizbekian Jun 14 '19 at 06:45
  • @azizbekian Sure, done, but sadly there is not much in it... Added some additional information about my styles/themes as well – prom85 Jun 14 '19 at 08:20
  • @prom85, I'm looking into sources of `TextView` and I can see that `SpannableStringBuilder.setSpan()` will be executed only in case when following is true: `if (text instanceof Spannable && !mAllowTransformationLengthChange)`. Can you debug and see if text is `instanceof Spannable`? – azizbekian Jun 14 '19 at 08:24
  • Can you try extracting string to a variable and then assigning it to the text field? TextView shouldn't be calling `setSpan` if your text is not Spannable. – Gokhan Arik Jun 18 '19 at 01:01
  • I now tried extracting the the string to a variable before setting it to the `TextView` - check my edit please, it still can crash... Again, this crash is very rare... – prom85 Jul 23 '19 at 11:51

1 Answers1

0

try

fun updateFilterInfo(showing: Int, total: Int) {
  binding?.tvFilterLvl1?.let {
    text = "$showing / $total"
  }
}
Dmytro Batyuk
  • 957
  • 8
  • 15