You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.26 09:42:45