I am currently having trouble with drawing to a custom SurfaceView
from a thread that is not on my main UI. This SurfaceView
takes up the entirety of the screen (Galaxy S3 in full screen) and must be updated from several sources.
The problem is that the custom SurfaceView
will not save changes between updates to UI.
The custom SurfaceView
class is defined within the activity that uses it, and the thread (let's call it DrawingThread
) that runs periodic checks for updates is defined within the custom SurfaceView
class. I have done this similar to this tutorial.
Another external thread is updating a list of changes that must be made to the UI. DrawingThread
checks this list every 50ms or so, and if the list is not empty, calculates a rectangle that must be redrawn.
// Thread waits for change request to UI or kill order
// Build Rect at point of Touch
try {
Canvas = _surfaceHolder.lockCanvas(Rect);
synchronized (_surfaceHolder) {
postInvalidate(); //Calls custom SurfaceView's onDraw() with the correct Canvas
}
} finally {
if (Canvas != null) {
_surfaceHolder.unlockCanvasAndPost(Canvas);
}
}
// Loop
My onDraw()
method for the custom SurfaceView
is below:
@Override
public void onDraw(Canvas canvas) {
// Initialize vars for rectangle
Paint.setStyle(Style.FILL);
for (MapChanges change : ExternalClass.getMapChanges()) {
// Build Rect at point of Touch
// Select Color for Paint
canvas.drawRect(Rect, Paint);
ExternalClass.removeMapChange(change); //Thread safe
}
}
This works flawlessly except for the fact that it is forgetting changes from any previous onDraw()
call. I am currently testing this by using an OnTouchListener
.
Code procedure as I understand it:
- Touch adds a change request for the UI to the list in the
ExternalClass
. DrawingThread
sees the list is no longer empty, safely grabs the Canvas, andpostInvalidates()
to call customSurfaceView
'sonDraw()
.onDraw()
updates the UI and removes the change request fromExternalClass
.DrawingThread
posts theCanvas
and goes back to waiting.
My expected behavior is that I will accumulate dots on my screen with successive touches. Instead, each touch clears the screen, leaving me with the background and exactly one dot where I last touched the screen.
I find this vastly confusing as lockCanvas(Rect)
specifically mentions that it will save changes between locks by designating a "dirty" section. Google searches have lead me to believe that most users find the opposite problem: that they want the View
redrawn but must do so every update manually.
Why is the program drawing a clean SurfaceView
from scratch each UI update despite my designation of a "dirty" section to redraw?
No doubt someone will reference me to this previously answered question where the programmer was advised to use bitmaps. I am trying to avoid this due to how new I am to this and my desire to not work with large amounts of memory (updating the UI is a tiny portion of my code). Working with simple shapes directly on a View
would be ideal for me. Additionally it is presented as a workaround. Is this a flaw in the Android API?
Have been searching here and Google for several hours now. Hope I have not missed anything blatantly obvious.