简体   繁体   中英

When a bitmap drawn via Canvas.drawBitmap() is actually drawn on the screen?

I have overridden the onDraw() method in a custom View. My method looks like following:

protected void onDraw(Canvas canvas) {
    super.onDraw(canvas);

    data.lockData(); // uses reentrantlock
    Bitmap bm = data.getBitmap();

    if (bm != null) {
        canvas.drawBitmap(bm,0,0,mPaint);
    }
    data.unlockData();
}

There is another thread that updates the bitmap, and this thread also uses the lockData() method to ensure serialized access to the bitmap. However, I see that the bitmap being drawn contains incomplete updates, ie it is being drawn to the screen while being in the middle of update by the other thread. I do not know the details of the Android drawing pipeline with sufficient detail (or actually with any detail:), but I assume this is due to that drawBitmap() does not actually draw the bitmap, but just places it into a draw operations queue with the pointer to the bitmap, and later another part of the system will use this pointer to copy the required part of the bitmap pixels to the buffer that will be displayed on screen. Therefore the actual drawing is not protected by the mutex.

There is a classical solution, ie double buffering, which I think could work in this type of situation. However, I still think that my draw thread might be so fast that it actually comes to update the buffer that is being drawn again before the actual draw has finished. Furthermore, my bitmap can be quite large, and allocating a separate buffer would be somewhat wasteful.

My questions are:

  1. Is my above stated understanding about the reason for incomplete draws correct, ie the drawBitmap returns before the bitmap data has actually been copied to the display? Could you provide a reference for details on how the drawing works?

  2. Is there a way to know when the bitmap has actually been drawn, and therefore it is again safe to modify the bitmap?

  3. If double buffering is the only solution, how can I ensure that buffer1 has finished drawing before allowing the buffer1 to be updated again with new data?

I was not able to make the View drawing synchronized. One way it would have worked is to do the calculation from within the onDraw() method, ie Bitmap bm = data.getBitmap(); would do calculate the updated bitmap. The drawback of this is that this will block the UI thread for the duration of the calculation, resulting or example in missed input events, etc.

One way this can be overcome is to use a SurfaceView instead. There one can do the calculation and drawing in a separate thread, thus serializing the two operations, while still leaving the UI thread free.

would image.setDrawingCacheEnabled(true);

do any good? Setting this to true enables you to pull a bitmap from the newly drawn canvas. Seems like that would be synchronized with the actual drawing so that when you subsequently do:

imageBitmap = image.getDrawingCache();

you would get a fully drawn image

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM