Android Question Strange results on Canvas with Panel.Invalidate2 and Panel.Invalidate3

max123

Well-Known Member
Licensed User
Longtime User
Hi all,

I had some problems with Canvas on my project, so decided to reproduce it in a small code to know what is the problem.

Can someone explain this ?

On this code:
  1. If I uncomment all pnl.Invalidate I see the first left green line, so even if I do not Invalidate the panel
  2. If I uncomment the pnl.Invalidate (OPTION 1) all was ok and the full panel is invalidated
  3. If I uncomment the pnl.Invalidate2 or pnl.Invalidate3 (OPTION 2, OPTION 3) I always see the first green line on the left, then it only invalidates the whole rectangle, but this only works if I set targetSdkVersion 13 on the manifest, with targetSdkVersion 14+ it invalidate the full panel not just the rectangle
I need to invalidate just a part of Canvas, what I doing wrong ?

Many thanks

Code:
Sub Process_Globals
    Private cols() As Int = Array As Int(Colors.Green, Colors.Magenta, Colors.Red, Colors.Cyan, Colors.Blue, Colors.White)
End Sub

Sub Globals
    Private pnl As Panel
    Private cvs As Canvas
End Sub

Sub Activity_Create(FirstTime As Boolean)
    'Activity.LoadLayout("Layout1")

    pnl.Initialize("pnl")
 
    Activity.AddView(pnl, 0, 0, 100%x, 100%y)
    cvs.Initialize(pnl)
    cvs.AntiAlias = True
    cvs.DrawColor(Colors.Black)
 
    Activity.Invalidate

    DoTest
End Sub

Sub Activity_Resume

End Sub

Sub Activity_Pause (UserClosed As Boolean)

End Sub

Sub DoTest
    Dim x As Float = 0
 
    Do While True
        Dim t1 As Long = DateTime.Now
 
        For Each c As Int In cols
            For x = 0 To 100%x  Step 1dip
                cvs.DrawLine(x, 0, x, 100%y, c, 1dip)
        
'                pnl.Invalidate  ' OPTION 1 (Invalidate the full panel)

'                Dim Rect1 As Rect
'                Rect1.Initialize(100dip, 100dip, 300dip, 300dip)
'                pnl.Invalidate2(Rect1)  ' OPTION 2 (Invalidate just a rectangle by rectangle)

                pnl.Invalidate3(100dip, 100dip, 300dip, 300dip)  ' OPTION 3 (Invalidate just a rectangle by coordinates)
                                                                        
                If x Mod 10 = 0 Then Sleep(0)
'                Sleep(100)
            Next
        Next
 
        t1 = DateTime.Now - t1
        Log("Required " & t1 & " Milliseconds")
    Loop
End Sub
 
Last edited:

max123

Well-Known Member
Licensed User
Longtime User
So no other people had this issue ?

In my project I use a big Canvas (3000x3000 pixels) inside a ScrollView2D to scroll it horizzontally and vertically, so with a big panel refresh the full panel is inpraticable, it require too much time to redraw, the app hang, I need to redraw just a part where I draw with Canvas functions.

My app control a 3D Printer over USB, while it send gcode file (line by line) to the printer, draw on this Canvas.

If I print long lines no problem, but with a lot of short lines line segments like in a circle the app need to be fast, if I set SDK 13 on the manifest this work well and the app only redraw the rectangle I need, If I set SDK 14 or greater this not happen, the app redraw the full panel,the draw slow down, the printing process slow down because redraw the full big panel require too much time.

Please help, I cannot develop....

Many Thanks
 
Last edited:
Upvote 0

Erel

B4X founder
Staff member
Licensed User
Longtime User
It is probably related to hardware acceleration. You cannot assume that only part of the panel will be invalidated.
Creating a huge canvas is a mistake. The correct solution is to:

1. Remove ScrollView2D and handle the movement yourself.
2. Only draw the visible region.

Two somewhat related solutions:
 
Upvote 1

max123

Well-Known Member
Licensed User
Longtime User
Hi @Erel , many thanks for reply.

So something changed from SDK 13 to >= 14, related to the Canvas ?

That even is hardware related is right, I test on two devices, an Asus Smartphone ZenPhone2 and a Nexus7 2013, if I set targetSdk >= 14 with both devices it redraw the full panel, but on Nexus7 that is a faster device the app completely hang when I show the page with the canvas. On the phone works but slow. To make it work on both devices I had to reduce the panel size like 1500x1500 and it worked but pretty slow refresh.

With targetSdk 13 it works well and fast on both devices.

In both cases a big panel + Canvas consume a lot of ram, if I increase the ScrollView2D size the app crash on startup with error that cannot allocate memory.

What I do not know is:
- In my app I've a slider to set the canvas refresh, if I set it to 10000, using SDK 13 it really draw 10000 lines, then redraw the panel, with SDK >= 14 this not happen, it just redraw every 100+ lines, do no matter if I change the slider to 10000 or 5000 or 1.

Today I will study your suggestions. ;)

Many Thanks
 
Last edited:
Upvote 0

agraham

Expert
Licensed User
Longtime User
Creating a 3000x3000 canvas will perform poorly.
From my experience there is a major problem with large canvases from SDK 14 onwards if you read the second paragraph here.

 
Upvote 0

max123

Well-Known Member
Licensed User
Longtime User
Note that when I started to develop my app (2018) I managed to use 3000dpi x 3000dpi, on my Nexus7 that have a scale factor of 2 are 6000x6000 pixels.
I do the same in the desktop version but pc have more ram and it do not have Android ?
 
Upvote 0

max123

Well-Known Member
Licensed User
Longtime User
@agraham this part of your post is like what I dreamed this night:
Having got the app working I then started looking to try to finally solve the image viewing problems and found some source code on GitHub that was written for just this purpose. Instead of loading the entire image at once it only fully decodes from the image file the areas needed for display. As a bonus the pre-zooming and centering is very accurate and works a treat. So after a bit of difficulty getting it to compile I wrapped it, slightly enhanced to draw a centered point indication and am now extremely happy with my mapping program that can now display huge images and target SDK version 26 and later without using a vast amount of memory.

That piece of code seem to be interesting to know to me...

Your class is like my, but I do not load images, I draw on it, I render 2D and static 3D, this worked pretty well and fast, I can zoom too. Yes is not an OpenGL view, but it just use a canvas, and is not a big class. I'm satisfacted with It, but now that I changed SDK Android do not like it.....

I already opened the Erel's HugeImageView class to search know what Erel do on it and adapt to my use case.
 
Last edited:
Upvote 0
Top