This repository was archived by the owner on Feb 25, 2025. It is now read-only.
-
Notifications
You must be signed in to change notification settings - Fork 6k
Ensure all images are closed in FlutterImageView #20842
Merged
Merged
Changes from 4 commits
Commits
Show all changes
6 commits
Select commit
Hold shift + click to select a range
File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -4,7 +4,6 @@ | |
|
||
package io.flutter.embedding.android; | ||
|
||
import android.annotation.SuppressLint; | ||
import android.annotation.TargetApi; | ||
import android.content.Context; | ||
import android.graphics.Bitmap; | ||
|
@@ -22,6 +21,8 @@ | |
import androidx.annotation.VisibleForTesting; | ||
import io.flutter.embedding.engine.renderer.FlutterRenderer; | ||
import io.flutter.embedding.engine.renderer.RenderSurface; | ||
import java.util.LinkedList; | ||
import java.util.Queue; | ||
|
||
/** | ||
* Paints a Flutter UI provided by an {@link android.media.ImageReader} onto a {@link | ||
|
@@ -35,11 +36,10 @@ | |
* an {@link android.media.Image} and renders it to the {@link android.graphics.Canvas} in {@code | ||
* onDraw}. | ||
*/ | ||
@SuppressLint("ViewConstructor") | ||
@TargetApi(19) | ||
public class FlutterImageView extends View implements RenderSurface { | ||
@NonNull private ImageReader imageReader; | ||
@Nullable private Image nextImage; | ||
@Nullable private Queue<Image> imageQueue; | ||
@Nullable private Image currentImage; | ||
@Nullable private Bitmap currentBitmap; | ||
@Nullable private FlutterRenderer flutterRenderer; | ||
|
@@ -70,17 +70,23 @@ public enum SurfaceKind { | |
* the Flutter UI. | ||
*/ | ||
public FlutterImageView(@NonNull Context context, int width, int height, SurfaceKind kind) { | ||
super(context, null); | ||
this.imageReader = createImageReader(width, height); | ||
this.kind = kind; | ||
init(); | ||
this(context, createImageReader(width, height), kind); | ||
} | ||
|
||
public FlutterImageView(@NonNull Context context) { | ||
this(context, 1, 1, SurfaceKind.background); | ||
} | ||
|
||
public FlutterImageView(@NonNull Context context, @NonNull AttributeSet attrs) { | ||
this(context, 1, 1, SurfaceKind.background); | ||
} | ||
|
||
@VisibleForTesting | ||
FlutterImageView(@NonNull Context context, @NonNull ImageReader imageReader, SurfaceKind kind) { | ||
super(context, null); | ||
this.imageReader = imageReader; | ||
this.kind = kind; | ||
this.imageQueue = new LinkedList<>(); | ||
init(); | ||
} | ||
|
||
|
@@ -150,12 +156,14 @@ public void detachFromRenderer() { | |
// attached to the renderer again. | ||
acquireLatestImage(); | ||
// Clear drawings. | ||
pendingImages = 0; | ||
currentBitmap = null; | ||
if (nextImage != null) { | ||
nextImage.close(); | ||
nextImage = null; | ||
|
||
// Close the images in the queue and clear the queue. | ||
for (final Image image : imageQueue) { | ||
image.close(); | ||
} | ||
imageQueue.clear(); | ||
// Close and clear the current image if any. | ||
if (currentImage != null) { | ||
currentImage.close(); | ||
currentImage = null; | ||
|
@@ -168,7 +176,10 @@ public void pause() { | |
// Not supported. | ||
} | ||
|
||
/** Acquires the next image to be drawn to the {@link android.graphics.Canvas}. */ | ||
/** | ||
* Acquires the next image to be drawn to the {@link android.graphics.Canvas}. Returns true if | ||
* there's an image available in the queue. | ||
*/ | ||
@TargetApi(19) | ||
public boolean acquireLatestImage() { | ||
if (!isAttachedToFlutterRenderer) { | ||
|
@@ -182,14 +193,14 @@ public boolean acquireLatestImage() { | |
// While the engine will also stop producing frames, there is a race condition. | ||
// | ||
// To avoid exceptions, check if a new image can be acquired. | ||
if (pendingImages < imageReader.getMaxImages()) { | ||
nextImage = imageReader.acquireLatestImage(); | ||
if (nextImage != null) { | ||
pendingImages++; | ||
if (imageQueue.size() < imageReader.getMaxImages()) { | ||
final Image image = imageReader.acquireLatestImage(); | ||
if (image != null) { | ||
imageQueue.add(image); | ||
} | ||
} | ||
invalidate(); | ||
return nextImage != null; | ||
return !imageQueue.isEmpty(); | ||
} | ||
|
||
/** Creates a new image reader with the provided size. */ | ||
|
@@ -200,15 +211,12 @@ public void resizeIfNeeded(int width, int height) { | |
if (width == imageReader.getWidth() && height == imageReader.getHeight()) { | ||
return; | ||
} | ||
// Close resources. | ||
if (nextImage != null) { | ||
nextImage.close(); | ||
nextImage = null; | ||
} | ||
imageQueue.clear(); | ||
if (currentImage != null) { | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. This There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Done. |
||
currentImage.close(); | ||
currentImage = null; | ||
} | ||
// Close all the resources associated with the image reader, | ||
// including the images. | ||
imageReader.close(); | ||
// Image readers cannot be resized once created. | ||
imageReader = createImageReader(width, height); | ||
|
@@ -218,16 +226,14 @@ public void resizeIfNeeded(int width, int height) { | |
@Override | ||
protected void onDraw(Canvas canvas) { | ||
super.onDraw(canvas); | ||
if (nextImage != null) { | ||
|
||
if (!imageQueue.isEmpty()) { | ||
if (currentImage != null) { | ||
currentImage.close(); | ||
pendingImages--; | ||
} | ||
currentImage = nextImage; | ||
nextImage = null; | ||
currentImage = imageQueue.poll(); | ||
updateCurrentBitmap(); | ||
} | ||
|
||
if (currentBitmap != null) { | ||
canvas.drawBitmap(currentBitmap, 0, 0, null); | ||
} | ||
|
@@ -238,6 +244,7 @@ private void updateCurrentBitmap() { | |
if (android.os.Build.VERSION.SDK_INT >= 29) { | ||
final HardwareBuffer buffer = currentImage.getHardwareBuffer(); | ||
currentBitmap = Bitmap.wrapHardwareBuffer(buffer, ColorSpace.get(ColorSpace.Named.SRGB)); | ||
buffer.close(); | ||
} else { | ||
final Plane[] imagePlanes = currentImage.getPlanes(); | ||
if (imagePlanes.length != 1) { | ||
|
@@ -255,7 +262,6 @@ private void updateCurrentBitmap() { | |
Bitmap.createBitmap( | ||
desiredWidth, desiredHeight, android.graphics.Bitmap.Config.ARGB_8888); | ||
} | ||
|
||
currentBitmap.copyPixelsFromBuffer(imagePlane.getBuffer()); | ||
} | ||
} | ||
|
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Add the import for
AttributeSet
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
🤦♂️