Skip to content
体验新版
项目
组织
正在加载...
登录
切换导航
打开侧边栏
sxychenjing
engine
提交
49d68053
E
engine
项目概览
sxychenjing
/
engine
与 Fork 源项目一致
从无法访问的项目Fork
通知
3
Star
0
Fork
0
代码
文件
提交
分支
Tags
贡献者
分支图
Diff
Issue
0
列表
看板
标记
里程碑
合并请求
0
Wiki
0
Wiki
分析
仓库
DevOps
项目成员
Pages
E
engine
项目概览
项目概览
详情
发布
仓库
仓库
文件
提交
分支
标签
贡献者
分支图
比较
Issue
0
Issue
0
列表
看板
标记
里程碑
合并请求
0
合并请求
0
Pages
分析
分析
仓库分析
DevOps
Wiki
0
Wiki
成员
成员
收起侧边栏
关闭侧边栏
动态
分支图
创建新Issue
提交
Issue看板
体验新版 GitCode,发现更多精彩内容 >>
未验证
提交
49d68053
编写于
9月 01, 2020
作者:
E
Emmanuel Garcia
提交者:
GitHub
9月 01, 2020
浏览文件
操作
浏览文件
下载
电子邮件补丁
差异文件
Ensure all images are closed in FlutterImageView (#20842)
上级
a7621430
变更
2
隐藏空白更改
内联
并排
Showing
2 changed file
with
113 addition
and
33 deletion
+113
-33
shell/platform/android/io/flutter/embedding/android/FlutterImageView.java
...ndroid/io/flutter/embedding/android/FlutterImageView.java
+39
-33
shell/platform/android/test/io/flutter/embedding/android/FlutterViewTest.java
...id/test/io/flutter/embedding/android/FlutterViewTest.java
+74
-0
未找到文件。
shell/platform/android/io/flutter/embedding/android/FlutterImageView.java
浏览文件 @
49d68053
...
...
@@ -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
;
...
...
@@ -15,6 +14,7 @@ import android.hardware.HardwareBuffer;
import
android.media.Image
;
import
android.media.Image.Plane
;
import
android.media.ImageReader
;
import
android.util.AttributeSet
;
import
android.view.Surface
;
import
android.view.View
;
import
androidx.annotation.NonNull
;
...
...
@@ -22,6 +22,8 @@ import androidx.annotation.Nullable;
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 +37,10 @@ import io.flutter.embedding.engine.renderer.RenderSurface;
* 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
nextImag
e
;
@Nullable
private
Queue
<
Image
>
imageQueu
e
;
@Nullable
private
Image
currentImage
;
@Nullable
private
Bitmap
currentBitmap
;
@Nullable
private
FlutterRenderer
flutterRenderer
;
...
...
@@ -70,17 +71,24 @@ public class FlutterImageView extends View implements RenderSurface {
* 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
)
{
/*package*/
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 +158,14 @@ public class FlutterImageView extends View implements RenderSurface {
// 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 +178,10 @@ public class FlutterImageView extends View implements RenderSurface {
// 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 +195,14 @@ public class FlutterImageView extends View implements RenderSurface {
// 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
())
{
nextI
mage
=
imageReader
.
acquireLatestImage
();
if
(
nextI
mage
!=
null
)
{
pendingImages
++
;
if
(
imageQueue
.
size
()
<
imageReader
.
getMaxImages
())
{
final
Image
i
mage
=
imageReader
.
acquireLatestImage
();
if
(
i
mage
!=
null
)
{
imageQueue
.
add
(
image
)
;
}
}
invalidate
();
return
nextImage
!=
null
;
return
!
imageQueue
.
isEmpty
()
;
}
/** Creates a new image reader with the provided size. */
...
...
@@ -200,15 +213,10 @@ public class FlutterImageView extends View implements RenderSurface {
if
(
width
==
imageReader
.
getWidth
()
&&
height
==
imageReader
.
getHeight
())
{
return
;
}
// Close resources.
if
(
nextImage
!=
null
)
{
nextImage
.
close
();
nextImage
=
null
;
}
if
(
currentImage
!=
null
)
{
currentImage
.
close
();
currentImage
=
null
;
}
imageQueue
.
clear
();
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 class FlutterImageView extends View implements RenderSurface {
@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 @@ public class FlutterImageView extends View implements RenderSurface {
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 @@ public class FlutterImageView extends View implements RenderSurface {
Bitmap
.
createBitmap
(
desiredWidth
,
desiredHeight
,
android
.
graphics
.
Bitmap
.
Config
.
ARGB_8888
);
}
currentBitmap
.
copyPixelsFromBuffer
(
imagePlane
.
getBuffer
());
}
}
...
...
shell/platform/android/test/io/flutter/embedding/android/FlutterViewTest.java
浏览文件 @
49d68053
...
...
@@ -12,12 +12,15 @@ import static org.mockito.Mockito.times;
import
static
org
.
mockito
.
Mockito
.
verify
;
import
static
org
.
mockito
.
Mockito
.
when
;
import
android.annotation.SuppressLint
;
import
android.annotation.TargetApi
;
import
android.content.Context
;
import
android.content.res.Configuration
;
import
android.content.res.Resources
;
import
android.graphics.Canvas
;
import
android.graphics.Insets
;
import
android.media.Image
;
import
android.media.Image.Plane
;
import
android.media.ImageReader
;
import
android.view.View
;
import
android.view.ViewGroup
;
...
...
@@ -550,6 +553,77 @@ public class FlutterViewTest {
verify
(
mockReader
,
times
(
2
)).
acquireLatestImage
();
}
@Test
public
void
flutterImageView_detachFromRendererClosesAllImages
()
{
final
ImageReader
mockReader
=
mock
(
ImageReader
.
class
);
when
(
mockReader
.
getMaxImages
()).
thenReturn
(
2
);
final
Image
mockImage
=
mock
(
Image
.
class
);
when
(
mockReader
.
acquireLatestImage
()).
thenReturn
(
mockImage
);
final
FlutterImageView
imageView
=
spy
(
new
FlutterImageView
(
RuntimeEnvironment
.
application
,
mockReader
,
FlutterImageView
.
SurfaceKind
.
background
));
final
FlutterJNI
jni
=
mock
(
FlutterJNI
.
class
);
imageView
.
attachToRenderer
(
new
FlutterRenderer
(
jni
));
doNothing
().
when
(
imageView
).
invalidate
();
imageView
.
acquireLatestImage
();
imageView
.
acquireLatestImage
();
imageView
.
detachFromRenderer
();
verify
(
mockImage
,
times
(
2
)).
close
();
}
@Test
@SuppressLint
(
"WrongCall"
)
/*View#onDraw*/
public
void
flutterImageView_onDrawClosesAllImages
()
{
final
ImageReader
mockReader
=
mock
(
ImageReader
.
class
);
when
(
mockReader
.
getMaxImages
()).
thenReturn
(
2
);
final
Image
mockImage
=
mock
(
Image
.
class
);
when
(
mockImage
.
getPlanes
()).
thenReturn
(
new
Plane
[
0
]);
when
(
mockReader
.
acquireLatestImage
()).
thenReturn
(
mockImage
);
final
FlutterImageView
imageView
=
spy
(
new
FlutterImageView
(
RuntimeEnvironment
.
application
,
mockReader
,
FlutterImageView
.
SurfaceKind
.
background
));
final
FlutterJNI
jni
=
mock
(
FlutterJNI
.
class
);
imageView
.
attachToRenderer
(
new
FlutterRenderer
(
jni
));
doNothing
().
when
(
imageView
).
invalidate
();
imageView
.
acquireLatestImage
();
imageView
.
acquireLatestImage
();
imageView
.
onDraw
(
mock
(
Canvas
.
class
));
imageView
.
onDraw
(
mock
(
Canvas
.
class
));
// 1 image is closed and 1 is active.
verify
(
mockImage
,
times
(
1
)).
close
();
verify
(
mockReader
,
times
(
2
)).
acquireLatestImage
();
// This call doesn't do anything because there isn't
// an image in the queue.
imageView
.
onDraw
(
mock
(
Canvas
.
class
));
verify
(
mockImage
,
times
(
1
)).
close
();
// Aquire another image and push it to the queue.
imageView
.
acquireLatestImage
();
verify
(
mockReader
,
times
(
3
)).
acquireLatestImage
();
// Then, the second image is closed.
imageView
.
onDraw
(
mock
(
Canvas
.
class
));
verify
(
mockImage
,
times
(
2
)).
close
();
}
/*
* A custom shadow that reports fullscreen flag for system UI visibility
*/
...
...
编辑
预览
Markdown
is supported
0%
请重试
或
添加新附件
.
添加附件
取消
You are about to add
0
people
to the discussion. Proceed with caution.
先完成此消息的编辑!
取消
想要评论请
注册
或
登录