Search code examples
androidkotlinandroid-textinputedittext

While Editing in TextInputEditText, App crashes in Android version 8.0 Samsung Exp 9.0


This is okay in other versions of ndroid but this error occurs in my android version 8 (Oreo) Samsung Experience 9.0.

Every time when I try to edit some existing data inside val lyricsEditor = view.findViewById<EditText>(R.id.lyrics_editor) , it crashes giving the logcat report as below.

I Tried by changing the typecast as val lyricsEditor = view.findViewById<TextInputEditText>(R.id.lyrics_editor) but the problem is same as before.

This okay when I start a new editor. But the problem occurs when I try to edit existing data

I couldn't figure out any issues. Please help me.

Logcat Shows

2023-01-30 14:03:54.222 AndroidRuntime E  FATAL EXCEPTION: main
   Process: com.rj.mysongbook, PID: 12196
   java.lang.ArrayIndexOutOfBoundsException: length=9; index=-1
    at android.text.DynamicLayout.getBlockIndex(DynamicLayout.java:646)
    at android.widget.Editor.drawHardwareAccelerated(Editor.java:1820)
    at android.widget.Editor.onDraw(Editor.java:1789)
    at android.widget.TextView.onDraw(TextView.java:7779)
    at android.view.View.draw(View.java:20370)
    at android.view.View.updateDisplayListIfDirty(View.java:19315)
    at android.view.View.draw(View.java:20093)
    at android.view.ViewGroup.drawChild(ViewGroup.java:4421)
    at android.view.ViewGroup.dispatchDraw(ViewGroup.java:4207)
    at android.view.View.updateDisplayListIfDirty(View.java:19306)
    at android.view.View.draw(View.java:20093)
    at android.view.ViewGroup.drawChild(ViewGroup.java:4421)
    at android.view.ViewGroup.dispatchDraw(ViewGroup.java:4207)
    at android.view.View.draw(View.java:20373)
    at com.google.android.material.textfield.TextInputLayout.draw(TextInputLayout.java:3906)
    at android.view.View.updateDisplayListIfDirty(View.java:19315)
    at android.view.View.draw(View.java:20093)
    at android.view.ViewGroup.drawChild(ViewGroup.java:4421)
    at android.view.ViewGroup.dispatchDraw(ViewGroup.java:4207)
    at android.view.View.updateDisplayListIfDirty(View.java:19306)
    at android.view.View.draw(View.java:20093)
    at android.view.ViewGroup.drawChild(ViewGroup.java:4421)
    at android.view.ViewGroup.dispatchDraw(ViewGroup.java:4207)
    at android.view.View.updateDisplayListIfDirty(View.java:19306)
    at android.view.View.draw(View.java:20093)
    at android.view.ViewGroup.drawChild(ViewGroup.java:4421)
    at android.view.ViewGroup.dispatchDraw(ViewGroup.java:4207)
    at android.view.View.updateDisplayListIfDirty(View.java:19306)
    at android.view.View.draw(View.java:20093)
    at android.view.ViewGroup.drawChild(ViewGroup.java:4421)
    at android.view.ViewGroup.dispatchDraw(ViewGroup.java:4207)
    at android.view.View.updateDisplayListIfDirty(View.java:19306)
    at android.view.View.draw(View.java:20093)
    at android.view.ViewGroup.drawChild(ViewGroup.java:4421)
    at android.view.ViewGroup.dispatchDraw(ViewGroup.java:4207)
    at android.view.View.updateDisplayListIfDirty(View.java:19306)
    at android.view.View.draw(View.java:20093)
    at android.view.ViewGroup.drawChild(ViewGroup.java:4421)
    at android.view.ViewGroup.dispatchDraw(ViewGroup.java:4207)
    at android.view.View.updateDisplayListIfDirty(View.java:19306)
    at android.view.View.draw(View.java:20093)
    at android.view.ViewGroup.drawChild(ViewGroup.java:4421)
    at android.view.ViewGroup.dispatchDraw(ViewGroup.java:4207)
    at android.view.View.updateDisplayListIfDirty(View.java:19306)
    at android.view.View.draw(View.java:20093)
    at android.view.ViewGroup.drawChild(ViewGroup.java:4421)
    at android.view.ViewGroup.dispatchDraw(ViewGroup.java:4207)
    at android.view.View.updateDisplayListIfDirty(View.java:19306)
    at android.view.View.draw(View.java:20093)
    at android.view.ViewGroup.drawChild(ViewGroup.java:4421)
    at android.view.ViewGroup.dispatchDraw(ViewGroup.java:4207)
    at android.view.View.draw(View.java:20373)
    at com.android.internal.policy.DecorView.draw(DecorView.java:980)
    at android.view.View.updateDisplayListIfDirty(View.java:19315)
    at android.view.ThreadedRenderer.updateViewTreeDisplayList(ThreadedRenderer.java:686)
    at android.view.ThreadedRenderer.updateRootDisplayList(ThreadedRenderer.java:692)
    at android.view.ThreadedRenderer.draw(ThreadedRenderer.java:800)
    at android.view.ViewRootImpl.draw(ViewRootImpl.java:3501)
    at android.view.ViewRootImpl.performDraw(ViewRootImpl.java:3288)
    at android.view.ViewRootImpl.performTraversals(ViewRootImpl.java:2823)
    at android.view.ViewRootImpl.doTraversal(ViewRootImpl.java:1785)
    at android.view.ViewRootImpl$TraversalRunnable.run(ViewRootImpl.java:7832)
    at android.view.Choreographer$CallbackRecord.run(Choreographer.java:911)
    at android.view.Choreographer.doCallbacks(Choreographer.java:723)
    at android.view.Choreographer.doFrame(Choreographer.java:658)
    at android.view.Choreographer$FrameDisplayEventReceiver.run(Choreographer.java:897)
    at android.os.Handler.handleCallback(Handler.java:789)
    at android.os.Handler.dispatchMessage(Handler.java:98)
    at android.os.Looper.loop(Looper.java:164)
    at android.app.ActivityThread.main(ActivityThread.java:6944)
    at java.lang.reflect.Method.invoke(Native Method)
    at com.android.internal.os.Zygote$MethodAndArgsCaller.run(Zygote.java:327)
    at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:1374)

My Layout is

<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical">

<com.google.android.material.textfield.TextInputLayout
    android:layout_width="match_parent"
    android:layout_height="wrap_content"
    android:layout_margin="10dp"
    android:hint="@string/lyrics_title"
    android:textColorHint="#EF1AF6"
    app:hintTextColor="@color/red">

    <com.google.android.material.textfield.TextInputEditText
        android:id="@+id/title_editor"
        style="@style/lyricsTvStyle"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:background="@drawable/square_edittext"
        android:textColor="@color/black" />
</com.google.android.material.textfield.TextInputLayout>


<com.google.android.material.textfield.TextInputLayout
    android:layout_width="match_parent"
    android:layout_height="wrap_content"
    android:layout_margin="10dp"
    android:hint="@string/song_lyrics"
    android:textColorHint="#EF1AF6"
    app:hintTextColor="@color/red">

    <com.google.android.material.textfield.TextInputEditText
        android:id="@+id/lyrics_editor"
        style="@style/lyricsTvStyle"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:background="@drawable/square_edittext"
        android:textColor="@color/blue" />
</com.google.android.material.textfield.TextInputLayout 
</LinearLayout>

And I am taking data from these to my server as

private fun showEditorNew(
    songContainer: SongContainer,
    isDelete: Boolean,
) {
    var songNumber = songContainer.songNumber
    val songTypes = songContainer.songType
    val othersType = songContainer.othersType
    val title = songContainer.title
    val lyrics = songContainer.lyrics
    val engLyrics = songContainer.engLyrics
    val motherNode = songContainer.motherNode


    val builder = AlertDialog.Builder(requireActivity(), R.style.DialogTheme)
    val view = LayoutInflater.from(activity).inflate(R.layout.editor_layout, null)
    view.keepScreenOn = true
    val titleEditor = view.findViewById<EditText>(R.id.title_editor)
    val lyricsEditor = view.findViewById<EditText>(R.id.lyrics_editor)

    titleEditor.setText(title)
    lyricsEditor.setText(lyrics)

    lyricsEditor.textAlignment = View.TEXT_ALIGNMENT_TEXT_START
    builder.setView(view)
    builder.setCustomTitle(requireContext().setCustomTitle("Song Editor"))
    builder.setCancelable(false)

    var posButton = "Edit"
    var snackMsg =
        "Edited!!! if you want to update, Click Edit Again!!!\nOr Click Cancel to go back!!!"
    if (isDelete) {
        posButton = "Delete"
        snackMsg =
            "Are you Sure to Delete?, Click Delete Again!!!\nOr Click Cancel to go back!!!"
    } else {
        builder.setNeutralButton(
            "Preview"
        ) { dialogInterface: DialogInterface?, i: Int -> }
    }
    builder.setPositiveButton(
        posButton
    ) { dialogInterface: DialogInterface?, i: Int -> }

    builder.setNegativeButton(
        "Cancel"
    ) { dialogInterface: DialogInterface, i: Int -> dialogInterface.dismiss() }
    val dialog = builder.create()
    dialog.show()

    dialog.getButton(DialogInterface.BUTTON_POSITIVE).setOnClickListener {
        if (isEditPermitted()) {
            if (!IsInternetAvailable(requireContext()).isConnected()) {
                showToast(getString(R.string.no_active_connection))
            } /*else if (!isEdit[0]) {
                showSnackBar(
                    snackMsg,
                    view,
                    true
                )
                isEdit[0] = true
                lyricsEditor.isFocusable = true
            }*/ else {
                val newTitle = titleEditor.text.toString().trim()
                val newLyrics = lyricsEditor.text.toString().trim()

                showToast("Editing in the server!!!")
                val songToDb =
                    HashMap<String, String>()
                songToDb["title"] = newTitle
                songToDb["lyrics"] = newLyrics

                if (songTypes != "null") {
                    songToDb["songType"] = songTypes
                }
                if (othersType != "null") {
                    songToDb["othersType"] = othersType
                }
                if (songNumber.contains(".")) {
                    songNumber = songNumber.split(".")[0].trim()
                }
                if (songNumber != "null") {
                    songToDb["songNumber"] = songNumber
                }
                if (engLyrics != "null") {
                    songToDb["engLyrics"] = engLyrics
                }

                val previewConfirm = requireContext().showWebPreview(newTitle, newLyrics)
                previewConfirm.setTitle("Are Sure to $posButton?")
                    .setIcon(R.drawable.ic_warning)
                previewConfirm.setPositiveButton("OK") { _, _ ->
                    newEditDb(motherNode, songToDb, dialog, isDelete)
                }
                    .setNegativeButton("Cancel", null)
                    .show()

            }
        }
    }

    dialog.getButton(DialogInterface.BUTTON_NEUTRAL).setOnClickListener { view1: View? ->
        if (titleEditor.text.isEmpty()) {
            requireContext().showAlert("No Title?", "Please give a title for this song")
        } else if (lyricsEditor.text.isEmpty()) {
            requireContext().showAlert("No Lyrics?", "Please write some Lyrics or paste here")
        } else {
            requireContext().showWebPreview(
                titleEditor.text.toString(),
                lyricsEditor.text.toString()
            )
                .setPositiveButton("OK", null)
                .show()
        }
    }
}

Solution

  • I have done some researches from your provided exception log, that is a known bug for Android 8.0.

    WordPress for Android had also encountered similar issue on Android 8.0 or 8.1 before.

    There is a version fix related to that:

    Fix DynamicLayout block index calculation after edit

    DynamicLayout made wrong adjustments to the block indices set to be redrawn. Every indice after the first change was being added the diff count in the blocks. However this meant when there are 2 deletes and an index as 1, it would become -1 (wrong array index). The change should be applied to indices outside of [firstBlock, lastBlock].

    And that's only available from Android 9 onwards.


    And one suggested fix provided, is to disable hardware acceleration on the targeted view.

    In code:

    lyricsEditor.setLayerType(View.LAYER_TYPE_SOFTWARE, null);
    

    Or in XML:

        <com.google.android.material.textfield.TextInputEditText
            android:id="@+id/lyrics_editor"
            style="@style/lyricsTvStyle"
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:background="@drawable/square_edittext"
            android:textColor="@color/blue"
            android:layerType="software" />