Delphi12中SurfaceView始终显示黑色背景,绘图无效果求助
Delphi 12 Android SurfaceView 绘图不显示问题排查
核心排查方向与解决方案
1. 画布锁定/提交流程缺失
SurfaceView绘图必须严格遵循获取画布→绘制→解锁提交的完整流程,这是内容显示的核心前提:
- 必须通过
FSurfaceHolder.lockCanvas()获取可绘制的JCanvas实例,不能直接创建画布对象。 - 绘制完成后必须调用
FSurfaceHolder.unlockCanvasAndPost(Canvas)提交内容,否则系统不会更新Surface显示。 - 额外注意:
lockCanvas()可能返回nil,需添加非空判断避免空指针异常。
示例修正代码:
var Canvas: JCanvas; begin Canvas := FSurfaceHolder.lockCanvas; if Assigned(Canvas) then begin try // 执行绘制操作,比如画一条白色线条 Canvas.drawLine(50, 50, 200, 200, FPaint); finally FSurfaceHolder.unlockCanvasAndPost(Canvas); // 必须提交画布 end; end; end;
2. 绘图线程未做有效性校验
在绘图线程中,必须循环检查Surface的有效性,否则Surface销毁后继续绘图会导致无效果甚至崩溃:
- 每次绘图前判断
FSurfaceHolder.getSurface.isValid(),无效时跳过本次循环并短暂休眠。 - 在
surfaceDestroyed回调中必须停止绘图线程,避免线程持有无效的Surface引用。
示例线程逻辑:
FDrawThread := TThread.CreateAnonymousThread(procedure begin FPaint := TJPaint.JavaClass.init; FPaint.setColor(TJColor.JavaClass.WHITE); // 确保画笔与黑色背景区分 FPaint.setStrokeWidth(8); while FIsRunning do begin // 检查Surface有效性 if not Assigned(FSurfaceHolder) or not FSurfaceHolder.getSurface.isValid then begin TThread.Sleep(10); Continue; end; // 执行绘图流程 var Canvas := FSurfaceHolder.lockCanvas; if Assigned(Canvas) then begin try // 可选:保留历史绘制则注释此行,需要刷新背景则开启 // Canvas.drawColor(TJColor.JavaClass.BLACK); Canvas.drawLine(FLastX, FLastY, FCurrentX, FCurrentY, FPaint); finally FSurfaceHolder.unlockCanvasAndPost(Canvas); end; end; TThread.Sleep(16); // 维持约60帧的绘制频率 end; end); FDrawThread.Start;
3. 画笔/画布颜色设置错误
- 确保画笔颜色与Surface默认黑色背景有明显区分,比如设置
FPaint.setColor(TJColor.JavaClass.WHITE)或其他亮色。 - 如果需要保留之前的绘制内容,不要在每次绘制时调用
Canvas.drawColor()清除背景;若需刷新背景,要先绘制背景再绘制内容。
4. JNI对象引用与线程安全问题
JSurfaceHolder对象必须在surfaceCreated回调中正确持有,避免被Delphi内存管理机制回收。- 触摸事件中记录的坐标需通过线程安全方式传递给绘图线程(比如用
TMonitor保护共享变量),避免坐标值混乱。
示例触摸事件处理:
procedure TMySurfaceViewCallback.OnTouchEvent(MotionEvent: JMotionEvent); begin case MotionEvent.getAction of AMOTION_EVENT_ACTION_DOWN: begin TMonitor.Enter(Self); try FLastX := MotionEvent.getX; FLastY := MotionEvent.getY; finally TMonitor.Exit(Self); end; end; AMOTION_EVENT_ACTION_MOVE: begin TMonitor.Enter(Self); try FCurrentX := MotionEvent.getX; FCurrentY := MotionEvent.getY; finally TMonitor.Exit(Self); end; end; end; end;
5. SurfaceView布局参数验证
- 确认SurfaceView的布局参数设置正确,比如
LayoutParams.width和height设为MATCH_PARENT或具体数值,避免控件尺寸为0导致看不到内容。 - 检查SurfaceView是否被其他控件遮挡,确保其处于窗口的顶层层级。
内容的提问来源于stack exchange,提问作者xuhui zhang
相关产品推荐
相关产品推荐

