如何使用单独的线程部分重绘自定义 SurfaceView 而不会丢失以前的编辑?

2024-06-19

我目前在按照自定义绘图时遇到问题SurfaceView来自不在我的主 UI 上的线程。这SurfaceView占据整个屏幕(Galaxy S3 全屏)并且必须从多个来源进行更新。

问题是习惯SurfaceView不会保存 UI 更新之间的更改。

习俗SurfaceView类是在使用它的活动和线程(我们称之为DrawingThread)运行定期检查更新是在自定义中定义的SurfaceView班级。我做了类似的事情本教程 http://danielnadeau.blogspot.com/2012/01/android-canvas-beginners-tutorial.html.

另一个外部线程正在更新必须对 UI 进行的更改列表。DrawingThread每 50 毫秒左右检查一次此列表,如果列表不为空,则计算必须重绘的矩形。

// 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()定制方法SurfaceView在下面:

@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
    }
}

除了忘记之前的任何更改之外,它的工作完美无缺onDraw()称呼。我目前正在使用OnTouchListener.

据我理解,代码流程:

  • Touch 将对 UI 的更改请求添加到列表中ExternalClass.
  • DrawingThread看到列表不再为空,安全地抓取 Canvas,并且postInvalidates()调用自定义SurfaceView's onDraw().
  • onDraw()更新 UI 并从中删除更改请求ExternalClass.
  • DrawingThread发布Canvas然后继续等待。

我的预期行为是,通过连续触摸,我会在屏幕上积累点。相反,每次触摸都会清除屏幕,只留下背景和我上次触摸屏幕的一个点。

我发现这非常令人困惑lockCanvas(Rect)特别提到它将通过指定“脏”部分来保存锁之间的更改。谷歌搜索让我相信大多数用户发现了相反的问题:他们想要View重绘,但每次更新都必须手动重绘。

为什么程序画得很干净SurfaceView尽管我指定了要重绘的“脏”部分,但每次 UI 更新还是从头开始?

毫无疑问有人会提到我这个之前回答过的问题 https://stackoverflow.com/questions/2949036/android-how-to-get-a-custom-view-to-redraw-partially建议程序员使用位图。我试图避免这种情况,因为我对此很陌生,并且我不想使用大量内存(更新 UI 只是我代码的一小部分)。直接在平面上处理简单的形状View对我来说是理想的。此外,它是作为一种解决方法提出的。这是 Android API 中的缺陷吗?

已经在这里和谷歌搜索了几个小时了。希望我没有错过任何明显的事情。


我设法找到了解决方法OnDraw()出等式。新的DrawingPanel below:

class DrawingPanel extends SurfaceView implements Runnable, SurfaceHolder.Callback {

    Thread thread = null;
    SurfaceHolder surfaceHolder;
    volatile boolean running = false;

    private Paint myPaint = new Paint(Paint.ANTI_ALIAS_FLAG);
    Random random;

    public DrawingPanel(Context context) {
        super(context);
        getHolder().addCallback(this);

        surfaceHolder = getHolder();
    }

    @Override 
    public void surfaceChanged(SurfaceHolder holder, int format, int width,
        int height) { 


    }

    @Override
    public void surfaceCreated(SurfaceHolder holder) {          
        setWillNotDraw(false); //Allows us to use invalidate() to call onDraw()

        if (!running) {
            running = true;
            thread = new Thread(this);
            thread.start();
        }
    }

    @Override
    public void surfaceDestroyed(SurfaceHolder holder) {
        try {
            running = false;    //Tells thread to stop
            thread.join();      //Removes thread from mem.
        } catch (InterruptedException e) {}
    }   

    @Override
    public void run() {
        Canvas canvas;
        Rect myRect = new Rect();
        boolean firstRun = true;

        ChangeRequest ChangeReq;

        myPaint.setStyle(Style.FILL);

        while(running) {
            try {
                Thread.sleep(50);
            } catch (Exception e) {}

            canvas = null;

            ChangeReq = getUIChangeRequests();

            if (!ChangeReq.isEmpty() || (firstRun)) {                   
                if(surfaceHolder.getSurface().isValid()) {
                    if (!firstRun) {  

                        // Calculate dirty space for editing
                        x = ChangeReq.getX();
                        y = ChangeReq.getY();

                        try {
                            myRect.set(x*RectSize, y*RectSize, x*RectSize + RectSize, y*RectSize + RectSize);
                            myPaint.setColor(Color.RED);

                            canvas = surfaceHolder.lockCanvas(myRect);

                            synchronized (surfaceHolder) {
                                // Draw
                                canvas.drawRect(myRect, myPaint);

                            }

                            // Remove ChangeRequest
                            ChangeReq.remove();

                        } finally {
                            if (canvas != null) {
                                surfaceHolder.unlockCanvasAndPost(canvas);
                            }
                        }
                    } else {
                        try {
                            // Initialize canvas as all one color
                            myRect.set(0, 0, getWidth(), getHeight());
                            myPaint.setColor(Color.DKGRAY);

                            canvas = surfaceHolder.lockCanvas();

                            synchronized (surfaceHolder) {
                                //Draw
                                canvas.drawRect(myRect, myPaint); 
                            }

                            firstRun = false;
                        } finally {
                            if (canvas != null) {
                                surfaceHolder.unlockCanvasAndPost(canvas);
                            }
                        }
                    }
                }
            }
        }
    }   
}

这解决了我的绘图问题,但提出了一个有趣的问题:为什么我必须使用surfaceHolder.lockCanvas();只有这样我才能使用surfaceHolder.lockCanvas(Rect);我会在另一个问题中问这个问题。

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

如何使用单独的线程部分重绘自定义 SurfaceView 而不会丢失以前的编辑? 的相关文章

随机推荐

  • MVC4 如何设置 cookie 然后重定向到操作

    您好 我正在尝试获取用户角色并将其设置为我的应用程序中的 cookie 我有以下有效的代码 public ActionResult Index var user User Identity Name set by 3rd party cen
  • 通过链接导航多个对象而不重复

    我正在尝试浏览一堆带有其他对象链接的对象 我想从 id 1 开始并浏览每个对象 有些对象会循环回到之前的对象 所以我想确保每个对象只查看一次 否则我会陷入无限循环 我还希望能够通过链接导航来判断哪些对象无法访问 我认为导航顺序并不重要 这是
  • BDD/TDD:依赖可以是一种行为吗?

    我被告知不要使用实施细节 依赖关系看起来像是一个实现细节 但我也可以将其表述为一种行为 示例 LinkList 依赖于存储引擎来存储其链接 例如 LinkStorageInterface 构造函数需要传递一个已实现的 LinkStorage
  • “ghs.google.com”域的机制是什么?

    如果我想给我的应用程序绑定一个域名GAE Google App Engine 我应该添加一条 CNAME 记录ghs google com 我想了解这个域名是如何运作的 例如 我有这样的 CNAME blog goace com ghs g
  • * foreach 里面的 foreach codeigniter 2?

    在 codeigniter 2 1 中 我尝试按类别显示频道 因此 如果我有一个名为 电影 的类别 我应该会看到电影中的频道列表 我尝试使用嵌套的 foreach 循环来完成此任务 但似乎无法使其工作 我的表结构是这样的 但更复杂 我的型号
  • strings.xml 中的 Android 变量

    我在某处读到如何在 XML 文档中使用变量 他们说这很简单 我想也是如此 我在 Android strings xml 文件中成功地使用了它 我一整天都这样使用它 直到突然 android 停止解析它并停止将它视为变量 我这样使用它
  • 一对一映射不适用于二级缓存

    我已经声明了 Hibernate 3 的以下映射 使用 FluentNHibernate public class ActivityMap ClassMap
  • 用渐变画线

    我在不同的位置画了多条线 例如 canvas drawLine startXLine1 stopXLine1 startYLine1 stopYLine1 paint canvas drawLine startXLine2 stopXLin
  • 为什么 fopen("any_path_name",'r') 不给出 NULL 作为返回值?

    在调试一些代码时 我得到如下内容 include
  • HTML表可选择行Javascript包[关闭]

    Closed 这个问题不符合堆栈溢出指南 help closed questions 目前不接受答案 Is there a Javascript package out there that makes table rows selecta
  • 在横向模式下向 UIScrollView 添加子视图

    我有一个以横向模式启动的视图控制器 其中有一个 UIScrollView 我尝试创建子视图并将它们添加到 UIScrollView 但视图的框架大小都是纵向大小 这是我的代码 void viewDidLoad super viewDidLo
  • Chrome 扩展:插入固定 div 作为 UI

    我想使用 chrome 扩展将 div 插入固定位置 它将覆盖您当前正在查看的页面 我担心的是 我希望它可以在任何页面上工作而不改变它 除了插入我的固定 div 之外 但我不知道我这样做的方式是否可行 目前 该按钮不会显示 并且我在让 di
  • Emoji 字符无法编码为 JSON

    我有一个UITextView我称之为messageField 其中的数据messageField is POST ed 以 JSON 格式发送到服务器 当用户输入表情符号字符时 我无法将数据编码为JSON 我认为 Emoji 使用 Unic
  • 顺序没有属性“validation_data”

    我从下面的链接下载并运行该文件https github com keunwoochoi keras callbacks example https github com keunwoochoi keras callbacks example
  • 确定虚拟内存的页表大小

    考虑一个具有 38 位虚拟字节地址 1KB 页和 512 MB 物理内存的虚拟内存系统 假设有效位 保护位 脏位和使用位总共占 4 位 并且所有虚拟页都在使用中 则本机上每个进程的页表总大小是多少 假设磁盘地址未存储在页表中 好吧 如果问题
  • 在 Python 3.8.0 中使用 pip 安装 numpy 时如何修复“错误:命令错误,退出状态 1”

    将Python升级到3 8 0后 我在使用pip安装与numpy相关的包时遇到问题 包括numpy matplotlib和sklearn 错误信息如下 我应该怎么做才能解决这个问题 C WINDOWS System32 gt pip ins
  • 全面的 html5 音频 API

    对于我的一生 我找不到所有 html5 的完整列表
  • 如何将两个图像放置在一个div的对角

    如你所见 我不是 CSS 专家 我需要一些帮助来了解如何使用两个图像制作这个 div 如下图所示 托马斯是对的 但还有更好的解决方案 div img class align left src alt description of your
  • *.hlsl 文件有什么作用,该文件和 *.fx 文件之间有什么关系?

    我正在阅读 DirectX 项目的示例 我看到 fx and hlsl files I know fx是DirectX读取的效果文件 但是它的用途是什么hlsl文件 这些文件有用吗 历史上fx包含使用效果系统语法的着色器 technique
  • 如何使用单独的线程部分重绘自定义 SurfaceView 而不会丢失以前的编辑?

    我目前在按照自定义绘图时遇到问题SurfaceView来自不在我的主 UI 上的线程 这SurfaceView占据整个屏幕 Galaxy S3 全屏 并且必须从多个来源进行更新 问题是习惯SurfaceView不会保存 UI 更新之间的更改