Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Welcome To Ask or Share your Answers For Others

Categories

0 votes
2.3k views
in Technique[技术] by (71.8m points)

android - Drawing to Surface from JNI while moving SurfaceView around

In my application I have a SurfaceView in my Activity layout so its surface is not affected by any Fragment lifecycles. I use the surface to draw to it from JNI using following code (some of the varialbes are global):

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);
        }
    }
}

As long as I do not change the size and position of the SurfaceView this works great. However, when I start drawing, adjust the SurfaceView in size and position (content is adjusted fine), stop the drawing and then start it again I get the following error:

E/BufferQueue: [SurfaceView] connect: already connected (cur=2, req=2)

What I understand from the documentation so far is that my SurfaceView is the consumer and the ANativeWindow the producer. The SurfaceView holds a BufferQueue which send the display data (copied by memcpy) from the producer to the consumer side. So after the size and location change one of them (I'm not sure which) is trying to connect to that BufferQueue again. Since in my code I'm not calling queue/acquire etc. specifically I'm not sure how to prevent this.

What I do not know: Is connect called from ANativeWindow_lock or ANativeWindow_fromSurface on the NDK side? Could the buffer received by the lock method leak somehow to prevent the connect next time? I also added log messages to the lock and unlock results and found that after the size and location change ANativeWindow_lock fails. This seems odd to me because my unlock is only performed when the lock was successful and I'm not locking the surface from the Java side at all. If I try to unlock it then from JNI I get:

Surface::unlockAndPost failed, no locked buffer

I also thought about other memory leaks and analysed it with LeakCanary. This does not find any leaks, even when I do a heap dump manually tho I'm not sure how good it works with native code.

If I do not draw at all this error does not appear. Do you have any ideas for this?

If it matters I'm developing on Android KitKat (4.4.2). Any help is highly appreciated.


与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome To Ask or Share your Answers For Others

1 Reply

0 votes
by (71.8m points)
等待大神答复

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
OGeek|极客中国-欢迎来到极客的世界,一个免费开放的程序员编程交流平台!开放,进步,分享!让技术改变生活,让极客改变未来! Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Click Here to Ask a Question

...