Android 移动SurfaceView时从JNI绘制到曲面

Android 移动SurfaceView时从JNI绘制到曲面,android,android-ndk,surfaceview,Android,Android Ndk,Surfaceview,在我的应用程序中,我的活动布局中有一个SurfaceView,因此它的表面不受任何片段生命周期的影响。我使用以下代码从JNI绘制曲面(一些变量是全局的): 只要我不改变SurfaceView的大小和位置,这就非常有效。但是,当我开始绘图时,调整SurfaceView的大小和位置(内容调整得很好),停止绘图,然后再次启动,我得到以下错误: E/BufferQueue:[SurfaceView]连接:已连接(cur=2,req=2) 到目前为止,我的SurfaceView是消费者,而ANativeW

在我的应用程序中,我的活动布局中有一个
SurfaceView
,因此它的表面不受任何片段生命周期的影响。我使用以下代码从JNI绘制曲面(一些变量是全局的):

只要我不改变
SurfaceView
的大小和位置,这就非常有效。但是,当我开始绘图时,调整
SurfaceView
的大小和位置(内容调整得很好),停止绘图,然后再次启动,我得到以下错误:

E/BufferQueue:[SurfaceView]连接:已连接(cur=2,req=2)

到目前为止,我的
SurfaceView
是消费者,而
ANativeWindow
是生产者。SurfaceView拥有一个
缓冲队列
,它将显示数据(由memcpy复制)从生产者发送到消费者端。因此,在更改大小和位置后,其中一个(我不确定是哪个)正在尝试再次连接到该缓冲队列。因为在我的代码中,我没有调用
队列/获取
等。具体来说,我不确定如何防止这种情况

我不知道的是:是从NDK侧的
ANativeWindow\u lock
调用连接还是从surface调用连接?锁方法接收到的缓冲区是否会泄漏以防止下次连接?我还向锁定和解锁结果中添加了日志消息,发现在更改大小和位置后,
ANativeWindow\u lock
失败。这对我来说似乎很奇怪,因为我的解锁只在锁定成功时执行,而我根本没有从Java端锁定曲面。如果我尝试解锁它,那么从JNI我会得到:

Surface::unlockAndPost失败,没有锁定的缓冲区

我还考虑了其他内存泄漏,并用LeakCanary进行了分析。这不会发现任何泄漏,即使我手动执行堆转储,但我不确定它在本机代码中的效果如何

如果我不画,这个错误就不会出现。你对此有什么想法吗


如果重要的话,我正在Android KitKat(4.4.2)上开发。非常感谢您的帮助。

调整曲面大小由SurfaceFlinger完成,您无法在调整/移动过程中绘制。您必须检测窗口何时移动/调整大小,并停止尝试锁定它以进行绘图。我在两个片段之间切换时调整SurfaceView的大小。所以你的意思是,我应该在事务期间锁定表面,并在事务结束时释放它?
lockCanvas
unlockCanvasAndPost
是正确的方法吗?当您要更改像素时,可以使用锁定/解锁:在当前处理同一曲面时,从do changes中预先设置其他(其他线程)。您必须释放所有锁(lockCanvas()的数量应与unlock()的数量相同),并等待直到曲面可以自由锁定或可用。如果我记得很清楚,有一种方法可以在尝试锁定画布之前检查SurfaceView的可用性。当SurfaceView由SurfaceFlinger(或其他人)持有时,您必须停止在其上绘制。然后您必须确保调用unlockCanvas()的时间与锁定方法的时间相同。感谢您的解释,我明天会尝试!但是为什么它第一次工作(只要我不停止画画,内容移动和缩放都很好)tho?
void onDraw() {
    int height=0, width=0;
    ANativeWindow_Buffer nativeBuffer;
    ARect redrawRect;

    if (nativeWindow != NULL) {
        height = ANativeWindow_getHeight(nativeWindow);
        width = ANativeWindow_getWidth(nativeWindow);

        redrawRect.left = 0;
        redrawRect.top = 0;
        redrawRect.right = width;
        redrawRect.bottom = height;
    
        if (ANativeWindow_lock(nativeWindow, &nativeBuffer, &redrawRect) == 0) {
            height = (redrawRect.bottom - redrawRect.top);
            width = (redrawRect.right - redrawRect.left);
    
            bufferSize= height * width * 4;
            memcpy(nativeBuffer.bits, pbuf, bufferSize);
            ANativeWindow_unlockAndPost(nativeWindow);
        }
    }
}