Android Question Crash on clicking selected CSBuilder text in EditText

Discussion in 'Android Questions' started by RB Smissaert, Oct 14, 2018.

  1. RB Smissaert

    RB Smissaert Well-Known Member Licensed User

    Have a simple EditText that has a CSBuilder text in it (for SQL syntax highlighting). When I select a length of text (with the normal standard long click) and then do a click within that text I get a crash with this error message:

    java.lang.IndexOutOfBoundsException: getChars (-1 ... 527) starts before 0
    at android.text.SpannableStringBuilder.checkRange(SpannableStringBuilder.java:1314)
    at android.text.SpannableStringBuilder.getChars(SpannableStringBuilder.java:1191)
    at android.text.TextUtils.getChars(TextUtils.java:98)
    at android.text.TextUtils.substring(TextUtils.java:289)
    at android.view.inputmethod.BaseInputConnection.getSelectedText(BaseInputConnection.java:532)
    at com.android.internal.view.IInputConnectionWrapper.executeMessage(IInputConnectionWrapper.java:286)
    at com.android.internal.view.IInputConnectionWrapper$MyHandler.handleMessage(IInputConnectionWrapper.java:85)
    at android.os.Handler.dispatchMessage(Handler.java:105)
    at android.os.Looper.loop(Looper.java:164)
    at android.app.ActivityThread.main(ActivityThread.java:6938)
    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)

    The problem is that I can't find where this error originates from. Running in debug mode does cause the same crash but it doesn't point to any B4A line. I tried stepping in debug mode by adding a Click event sub:

    Code:
    Sub edtSQL_Click()
        
    Log("edtSQL_Click")
    End Sub
    But that doesn't lead me to the origin of the error either.

    In case it matters the CSBuilder text does have clickable words, but the error also happens when clicking outside these clickable words. If formatting is turned off, so if the EditText holds plain text
    then there is no error.

    I am using the latest version of B4A and also the latest Android version.

    RBS
     
  2. Semen Matusovskiy

    Semen Matusovskiy Well-Known Member Licensed User

    It's hard to say without code ... Meanwhile in case Of CSBuilder you mast avoid retrieving string using EditText1.Text.
    In EditTextWrapper getText looks so
    Code:
    public String getText()  {  return ((TextView)getObject()).getText().toString();  }
    Try to use JavaObject
    Code:
    Dim jo As JavaObject
    Dim charsequenceFullText  As CSBuilder
    ...
    jo = EditText1
    charsequenceFullText = jo.RunMethod (
    "getText"Null)
    If need to take substring use subSequence, for example
    Code:
    Dim intSelectionStart As Int
    Dim charsequenceTextBeforeSelection As CSBuilder

    jo = charsequenceFullText
    intSelectionStart = EditText1.SelectionStart
    charsequenceTextBeforeSelection  = jo.RunMethod (
    "subSequence"Array (0, intSelectionStart))
     
    Last edited: Oct 14, 2018
  3. RB Smissaert

    RB Smissaert Well-Known Member Licensed User

    > It's hard to say without code

    What is relevant code though? There is no code in the edtSQL_Click event.
    Clicking in selected text should just alter the selection but I have no event code for that as far as I can see.

    Will have a look at your first suggestion.
    Subseqeuence I am using already.

    RBS
     
  4. Semen Matusovskiy

    Semen Matusovskiy Well-Known Member Licensed User

    Probably, something wrong in internal structure of CSBuilder "strings".
    I used CSBuilder in memory only, so I never converted them to sequence of bytes.
    Meanwhile you mentioned "SQL". Means you read/write CharSequences. How ?
     
  5. RB Smissaert

    RB Smissaert Well-Known Member Licensed User

    > converted them to sequence of bytes

    Not sure what you mean with that. I don't do this.
    The CSBuilder strings are used to colour syntax the SQL in that EditText view (edtSQL).

    How do I check the internal structure of the CSBuilder strings?
    They all show fine in the EditText.

    RBS
     
  6. Semen Matusovskiy

    Semen Matusovskiy Well-Known Member Licensed User

    Where do you take strings, which you show in EditText ?
    You create them in memory or you read them from external sources (for example, from DataBase) ?
    In first case it's possible to expect correct internal structure. In second case - all is possible . That's why I thought about internal structure.
     
    Last edited: Oct 15, 2018
  7. RB Smissaert

    RB Smissaert Well-Known Member Licensed User

    > Where do you take strings, which you show in EditText ?

    They are either directly typed in by the user or they are loaded from database where they are stored as simple strings.
    Well, I thought it was simple text, but looking at your previous post maybe not:

    Code:
    strSQL = edtSQL.Text
    SaveSQL(strSQL, strName) 
    'save to DB
    Will have a look at your Java method to get the pure text.

    RBS
     
  8. RB Smissaert

    RB Smissaert Well-Known Member Licensed User

    Are you saying that instead of:

    Code:
    strSQL = edtSQL.Text
    I should do:

    Code:
    Sub GetCSBuilderText(oView As ViewAs String
     
     
    Dim jo As JavaObject
     
    Dim charsequenceFullText  As CSBuilder

     jo = oView
     charsequenceFullText = jo.RunMethod (
    "getText"Null)
     
    Return charsequenceFullText.ToString

    End Sub
    And then:

    Code:
    strSQL = GetCSBuilderText(edtSQL)
    RBS
     
  9. Erel

    Erel Administrator Staff Member Licensed User

    That's not correct.

    That's probably not correct as well.

    I don't understand this one.

    Lets start from scratch.

    Where is the code that builds the CSBuilder?
     
  10. RB Smissaert

    RB Smissaert Well-Known Member Licensed User

    > Where is the code that builds the CSBuilder?

    Thanks, will post that code in a few hours.

    RBS
     
  11. Erel

    Erel Administrator Staff Member Licensed User

    The best you can do is to create a small program that creates the problematic CSBuilder and upload it.
     
  12. RB Smissaert

    RB Smissaert Well-Known Member Licensed User

    OK, will do that.

    RBS
     
  13. Semen Matusovskiy

    Semen Matusovskiy Well-Known Member Licensed User

    Erel --

    About your comment "That's not correct" relative
    Try Dim cs As CSBuilder = edittext1.Text
    Compiler will wrote:
    And what to do ? If to use Dim stringText As String = edittext1.Text, formatting will be lost
     
  14. Erel

    Erel Administrator Staff Member Licensed User

    I don't see how it is related to the OP question. This thread is already too "noisy" to be helpful. Please start a new thread for any other discussion.
     
    Star-Dust likes this.
  15. RB Smissaert

    RB Smissaert Well-Known Member Licensed User

    Solved the problem, but not really found the cause of it.
    The SQL string to be put in the EditText (edtSQL) didn't actually come directly from the database but from a TableView control (Table CustomView by Erel/Klaus).

    This is the code retrieving the SQL text (pure text, not CSBuilder text) and dumping it to the EditText:

    Code:
    Sub btnLoadSQL_Click() 'runs from list of saved SQL
     
     
    Dim strSQL As String
     
    Dim strSQL2 As String
     
    Dim cs As CSBuilder
     
     
    'iSavedSQLRow is produced by table row-click event
     tSavedSQL.Name = tblSavedSQL.GetValue(0, iSavedSQLRow)
     General.RunLog(
    "btnLoadSQL_Click, tSavedSQL.Name: " & tSavedSQL.Name)
     
     
    'this is fine, no error on clicking selected text
    '--------------------------------------------------
     strSQL = General.SQL1.ExecQuerySingleResult2("SELECT SQL FROM SQL WHERE NAME = ?"Array As String(tSavedSQL.Name))
     General.RunLog(
    "btnLoadSQL_Click, strSQL:")
     General.RunLog(strSQL)
     
     
    'this one will cause error on clicking selected text (only if CSBuilder text)
    '---------------------------------------------------------------------------------
     strSQL2 = tblSavedSQL.GetValue(3, iSavedSQLRow)
     General.RunLog(
    "btnLoadSQL_Click, strSQL2:")
     General.RunLog(strSQL2)
     
     
    'this will produce True, so strSQL = strSQL2
     General.RunLog("btnLoadSQL_Click, strSQL = strSQL2: " & General.Boolean2String(strSQL = strSQL2))
     
     lblOpenedSQL.Text = tSavedSQL.Name
     
     
    If bNoSQLFormattingAtAll Then
      edtSQL.Text = strSQL
     
    Else
      cs = FormatSQL(strSQL, 
    Null, -1, -1)
      bNoSQLFormatting = 
    True
      edtSQL.Text = cs
      bNoSQLFormatting = 
    False
     
    End If

     GotoPanel(ePanelType.SQLEdit, 
    FalseTrue)
     
    End Sub
    Now I thought let's get the SQL string directly from the DB instead and see if that fixes the problem.
    Strangely enough it does, although as far as I can see the 2 retrieved strings are exactly the same as
    demonstrated in the above code.
    I don't understand this at all. I will examine the 2 strings more thoroughly, byte for byte, but as far as I know
    if strSQL = strSQL2 then all the bytes must be the same as well.


    RBS
     
  16. Erel

    Erel Administrator Staff Member Licensed User

    Can you post the logs?
    If the strings are equal then the problem is somewhere else.

    This is not needed:
    Code:
    bNoSQLFormatting = True
      edtSQL.Text = cs
      bNoSQLFormatting = 
    False
     
  17. RB Smissaert

    RB Smissaert Well-Known Member Licensed User

    I posted the logs already. Or do you want something else?
    I know it is very strange, but for sure swapping strSQL and strSQL2 will clear or cause the mentioned problem.

    RBS
     
  18. Erel

    Erel Administrator Staff Member Licensed User

    All I can say from the information that I see is that if the strings are equal then it doesn't matter where they come from.
     
  19. RB Smissaert

    RB Smissaert Well-Known Member Licensed User

    Yes, agree with that and just noticed another crash, but it is a lot less frequent.
    Will see if I can reproduce in a small demo.

    RBS
     
  20. RB Smissaert

    RB Smissaert Well-Known Member Licensed User


    This is the code that builds the CSBuilder:

    Code:
    Sub InitSQLColours
     SQLColours(
    0) = Colors.RGB(000)
     SQLColours(
    1) = Colors.RGB(00220)
     SQLColours(
    2) = Colors.RGB(200600)
     SQLColours(
    3) = Colors.RGB(00220)
     SQLColours(
    4) = Colors.RGB(22000)
     SQLColours(
    5) = Colors.RGB(22000)
     SQLColours(
    6) = Colors.RGB(080255)
     SQLColours(
    7) = Colors.RGB(1280255)
     SQLColours(
    8) = Colors.RGB(02000'literal
     SQLColours(9) = Colors.RGB(1281280'for brackets
     SQLColours(10) = Colors.RGB(1401000'for table names
     SQLColours(11) = Colors.RGB(0140100'for view names
     SQLColours(12) = Colors.RGB(10032200'for SQL replace strings
     SQLColours(13) = Colors.RGB(10032200'for variable SQL replace strings
     SQLColours(14) = Colors.RGB(10032200'for custom function, for now only SD2XLD and CDMinusXDays
    End Sub

    Sub FormatSQL(strSQL As StringAs CSBuilder

     
    Dim i As Int
     
    Dim cs As CSBuilder
     
    Dim arrSQLWords() As SQLWord
     
    Dim UB As Int
     
    Dim strWordLower As String
     
    Dim tf As Typeface

     tf = 
    Typeface.CreateNew(Typeface.MONOSPACE, Typeface.STYLE_ITALIC)

     cs.Initialize.Color (
    Colors.Black)

     
    If bNoSQLFormattingAtAll Or bNoSQLFormatting Then
      
    Return cs
     
    End If

     
    'note that we shouldn't remove comments here as otherwise the SQL in the editor will change!
     '-------------------------------------------------------------------------------------------
     'this is very quick, about 1 msecs
     arrSQLWords = GetSQLWords(strSQL, 0""FalseFalse)
     
    ' For i = 0 To arrSQLWords.Length - 1
     '  General.RunLog("FormatSQL, Word: |" & arrSQLWords(i).strWord & "|")
     ' Next

     
    If arrSQLWords.Length = 0 Then
      
    Return cs
     
    End If

     General.StartSW (
    3)

     UB = arrSQLWords.Length - 
    1

     
    For i = 0 To UB
      
    'General.RunLog("FormatSQL, Word: " & arrSQLWords(i).strWord)

      
    If arrSQLWords(i).bWord Then
       
    If arrSQLWords(i).bLiteral Or arrSQLWords(i).bCommentStart Or arrSQLWords(i).bComment Or arrSQLWords(i).bCommentEnd Then
        
    'green for literal string or comment
        '-----------------------------------
        If arrSQLWords(i).bLiteral Or arrSQLWords(i).bComment Then
         cs.Color(SQLColours(
    8)).Append(arrSQLWords(i).strWord).Pop
        
    Else
         cs.Color(SQLColours(
    4)).Append(arrSQLWords(i).strWord).Pop
        
    End If
       
    Else    'If arrSQLWords(i).bLiteral
        strWordLower = arrSQLWords(i).strWord.ToLowerCase
        
    If mapSQLWordTypes.ContainsKey(strWordLower) Then
         
    Select Case mapSQLWordTypes.Get(strWordLower)
          
    Case 1
           
    'deal with SQL key word in square brackets or double quotes
           'no need to check previous byte as if not matching, SQL will fail Prepare
           '------------------------------------------------------------------------
           If arrSQLWords(i).lPos > 0 And _
                                (arrSQLWords(i).btNextByte = 
    34 Or arrSQLWords(i).btNextByte = 93Then
            cs.Append (arrSQLWords(i).strWord)
           
    Else
            cs.Bold.Color(SQLColours(
    1)).Append(arrSQLWords(i).strWord).Pop.Pop
           
    End If
          
    Case 2
           cs.Bold.Color(SQLColours(
    2)).Append(arrSQLWords(i).strWord).Pop.Pop
          
    Case 3
           cs.Color(SQLColours(
    3)).Append(arrSQLWords(i).strWord).Pop
          
    Case 4
           cs.Color(SQLColours(
    4)).Append(arrSQLWords(i).strWord).Pop
          
    Case 5
           cs.Color(SQLColours(
    4)).Append(arrSQLWords(i).strWord).Pop
          
    Case 6
           cs.Color(SQLColours(
    6)).Append(arrSQLWords(i).strWord).Pop
          
    Case 7
           cs.Color(SQLColours(
    7)).Append(arrSQLWords(i).strWord).Pop
          
    Case 10
           
    'tables, take care for fields that have same name as a table or view
           '-------------------------------------------------------------------
           If arrSQLWords(i).strPreviousWord.ToLowerCase = "from" Or _
                               arrSQLWords(i).strPreviousWord.ToLowerCase = 
    "join" Or _
                               arrSQLWords(i).strPreviousWord.ToLowerCase = 
    "table" Or _
                               arrSQLWords(i).strPreviousWord.ToLowerCase = 
    "into" Or _
                               arrSQLWords(i).strPreviousWord.ToLowerCase = 
    "update" Or _
                               arrSQLWords(i).strPreviousWord.ToLowerCase = 
    "exists" Then
            cs.Underline.Bold.Color(SQLColours(
    11)).Clickable("Table", _
                                           arrSQLWords(i).strWord).Append(arrSQLWords(i).strWord).Pop.Pop.Pop.Pop
           
    Else
            cs.Append (arrSQLWords(i).strWord)
           
    End If
          
    Case 11
           
    'views, take care for fields that have same name as a table or view
           '-----------------------------------------------------------------
           If arrSQLWords(i).strPreviousWord.ToLowerCase = "from" Or _
                               arrSQLWords(i).strPreviousWord.ToLowerCase = 
    "join" Or _
                               arrSQLWords(i).strPreviousWord.ToLowerCase = 
    "view" Then
            cs.Underline.Bold.Color(SQLColours(
    11)).Clickable("View", _
                                          arrSQLWords(i).strWord).Append(arrSQLWords(i).strWord).Pop.Pop.Pop.Pop
           
    Else
            cs.Append (arrSQLWords(i).strWord)
           
    End If
          
    Case 12
           
    'SQL replace strings
           cs.Underline.Color(SQLColours(12)).Clickable("Shortcut", _
                                         arrSQLWords(i).strWord).Append(arrSQLWords(i).strWord).Pop.Pop.Pop
          
    Case 13
           
    'SQL replace strings, based on variable
           cs.Typeface(tf).Underline.Color(SQLColours(13)).Clickable("VariableShortcut", _
                                         arrSQLWords(i).strWord).Append(arrSQLWords(i).strWord).Pop.Pop.Pop.Pop
          
    Case 14
           
    'custom SQL functions for now only SD2XLD
           cs.Typeface(tf).Color(SQLColours(6)).Append(arrSQLWords(i).strWord).Pop.Pop
         
    End Select
        
    Else    'If  mapSQLWordTypes.ContainsKey(strWordLower)
         'cs.Color(SQLColours(0)).Append(arrSQLWords(i).strWord).Pop
         cs.Append (arrSQLWords(i).strWord)
        
    End If    'If  mapSQLWordTypes.ContainsKey(strWordLower)
       End If    'If arrSQLWords(i).bLiteral
      Else    'If arrSQLWords(i).bWord
       If arrSQLWords(i).strWord.Trim.Length = 0 Then
        cs.Append (arrSQLWords(i).strWord)
       
    Else
        
    'only problem with this is that commas and % will be done like brackets
        cs.Color(SQLColours(9)).Append(arrSQLWords(i).strWord).Pop
       
    End If
      
    End If    'If arrSQLWords(i).bWord
     Next

     cs.PopAll

     cs.EnableClickEvents (edtSQL)
     
    'formatting takes a bit longer about 7 msecs for the Sudoku SQL
     '--------------------------------------------------------------
     'General.RunLog ("FormatSQL, time Formatting: " & General.StopSW(3) & " msecs")
     Return cs

    End Sub
    There is a lot of other code involved, but maybe somebody can spot a possible problem here.


    RBS
     
Loading...
  1. This site uses cookies to help personalise content, tailor your experience and to keep you logged in if you register.
    By continuing to use this site, you are consenting to our use of cookies.
    Dismiss Notice