Android Question Lazyloading BCTextEngine (ExternalRuns, B4X Code highlighter)

Toky Olivier

Active Member
Licensed User
Longtime User
Hello,
I'm using the B4X Code Highlighter posted by @Erel here: https://www.b4x.com/android/forum/threads/b4x-bctextengine-parser-b4x-code-highlighter.109308/
It's easy to understand and to modify it. My only problem now is, when the Code is long (eg. Twice of the length of the sample code in the tuto), parsing and drawing took times.
It seems that the LazyLoading property of BBCodeView doesn't work on ExternalRuns like with the B4XCodeHighlighter.
Can someone tell me how implement LazyLoading in that example please? Thank you
 

Toky Olivier

Active Member
Licensed User
Longtime User
Lazy loading doesn't affect parsing, only drawing
Ah, I see. In fact, the scrolling is very smooth. So it's the parsing the problem.
In the part:
B4X:
BBCodeView1.ExternalRuns = Highlighter.Parse(File.ReadString(File.DirAssets, "Code.txt"))
Is it not possible to Parse only the visible parts + X lines of code and we parse while scrolling the other parts after?
 
Upvote 0

Erel

B4X founder
Staff member
Licensed User
Longtime User
Are you testing it in release mode?

Is it not possible to Parse only the visible parts + X lines of code and we parse while scrolling the other parts after?
It is currently not possible. It is not so simple as each line can have a different height.

You can probably optimize the parsing code.
On a Google Pixel 2 it takes ~60ms to parse the example code. This is fast enough to handle 4 times longer code.
B4X:
For i = 1 To 10
        Dim n As Long = DateTime.Now
        BBCodeView1.ExternalRuns = Highlighter.Parse(File.ReadString(File.DirAssets, "Code.txt"))
        Log(DateTime.Now - n)
    Next
 
Upvote 0

Toky Olivier

Active Member
Licensed User
Longtime User
Yes, I'm testing on release mode.
I'm using an quite old phone: Android 5.0 with 3Go of Ram and the result is:
B4X:
** Activity (main) Pause, UserClosed = true **~i:** Activity (main) Create, isFirst = false **~l15720915:631
456
483
465
456
506
439~l85720915:489
473
458
** Activity (main) Resume **

It's not so fast.
If I limit Parsing to 20 lines only for example, the result is:

B4X:
*** Service (starter) Create ***
** Service (starter) Start **
** Activity (main) Create, isFirst = true **
110
128~l35720915:93
97
90
92
97
107
123
135
** Activity (main) Resume **
It's faster. So my Idea is, parsing only 20 lines and then continue parsing and append newly parsed Runs in the ExternalRuns variable of BBCodeView1.
Is it ok if I do like that?
 
Upvote 0

Toky Olivier

Active Member
Licensed User
Longtime User
It is not always the best idea to develop with a low end phone
I'm developing small app mainly for Malagasy (from Madagascar) people so I should test for "mid-range devices" from here.

Parse the first X characters, set the external runs, call Sleep(50) to let the code appear, parse everything.

I implemented like this, how do you think?
I created one sub:
B4X:
Public Sub ContinueParsing (CodeView As BBCodeView, Code As String, fromLine As Int, UpdateEveryLineCount As Int) As ResumableSub
    Dim runs As List
    runs.Initialize
    #if B4J
    Dim fx As JFX
    Dim monospace As Font = fx.CreateFont("Consolas", FontSize, False, False)
    Dim MonospaceBold As Font = fx.CreateFont("Consolas", FontSize, True, False)
    #Else If B4A
    Dim monospace As Typeface = Typeface.CreateNew(Typeface.MONOSPACE, Typeface.STYLE_NORMAL)
    Dim MonospaceBold As Typeface = Typeface.CreateNew(Typeface.MONOSPACE, Typeface.STYLE_BOLD)
    #Else If B4i
    Dim monospace As Font = Font.CreateNew2("DevanagariSangamMN", FontSize)
    Dim MonospaceBold As Font = Font.CreateNew2("DevanagariSangamMN-Bold", FontSize)
    #End If
    DefaultFont = xui.CreateFont(monospace, FontSize)
    DefaultBoldFont = xui.CreateFont(MonospaceBold, FontSize)
    Dim LineNumber As Int = fromLine + 1
    Dim NewlyParsed As Int = 0
    For Each Line As String In Regex.Split("\r?\n", Code)
        LineNumber = LineNumber + 1
        runs.Add(CreateLineNumber(LineNumber))
        runs.AddAll(ParseLine(Line))
        CreateRun(CRLF, TOKEN_DEFAULT, runs)
        NewlyParsed = NewlyParsed + 1
        If NewlyParsed = UpdateEveryLineCount Then
            CodeView.ExternalRuns.AddAll(runs)
            'CodeView.Redraw
            Log("New parsed lines")
            Sleep(50)
            
            Dim runs As List
            runs.Initialize
            NewlyParsed = 0
        End If
    Next
    
    CodeView.ExternalRuns.AddAll(runs)
    CodeView.ParseAndDraw
    Sleep(50)
    
    Return runs
End Sub

Now, visually, the parsing "seems fast". The code is immediatly shown. But if I scroll immediatly, there is a lag when I call "CodeView.Redraw" or "CodeView.ParseAndDraw". If I call them in the loop, the effect is not good at all... I prefered for now drawing when all the code is parsed.
Enclosed the modified sample.
 

Attachments

  • BBCodeViewParsing.zip
    14.1 KB · Views: 106
Upvote 0
Top