未验证 提交 52791326 编写于 作者: M Matt Carroll 提交者: GitHub

Android Embedding PR27: Fix SurfaceView flicker in Fragment transactions (#8504)

上级 86ab45cd
......@@ -273,6 +273,7 @@ public class FlutterActivity extends FragmentActivity implements OnFirstFrameRen
.appBundlePath(getAppBundlePath())
.flutterShellArgs(FlutterShellArgs.fromIntent(getIntent()))
.renderMode(FlutterView.RenderMode.surface)
.transparencyMode(FlutterView.TransparencyMode.opaque)
.build();
}
......
......@@ -65,6 +65,7 @@ public class FlutterFragment extends Fragment {
private static final String ARG_APP_BUNDLE_PATH = "app_bundle_path";
private static final String ARG_FLUTTER_INITIALIZATION_ARGS = "initialization_args";
private static final String ARG_FLUTTERVIEW_RENDER_MODE = "flutterview_render_mode";
private static final String ARG_FLUTTERVIEW_TRANSPARENCY_MODE = "flutterview_transparency_mode";
/**
* Builder that creates a new {@code FlutterFragment} with {@code arguments} that correspond
......@@ -82,6 +83,7 @@ public class FlutterFragment extends Fragment {
private String appBundlePath = null;
private FlutterShellArgs shellArgs = null;
private FlutterView.RenderMode renderMode = FlutterView.RenderMode.surface;
private FlutterView.TransparencyMode transparencyMode = FlutterView.TransparencyMode.transparent;
/**
* The name of the initial Dart method to invoke, defaults to "main".
......@@ -135,6 +137,18 @@ public class FlutterFragment extends Fragment {
return this;
}
/**
* Support a {@link FlutterView.TransparencyMode#transparent} background within {@link FlutterView},
* or force an {@link FlutterView.TransparencyMode#opaque} background.
* <p>
* See {@link FlutterView.TransparencyMode} for implications of this selection.
*/
@NonNull
public Builder transparencyMode(@NonNull FlutterView.TransparencyMode transparencyMode) {
this.transparencyMode = transparencyMode;
return this;
}
@NonNull
public FlutterFragment build() {
FlutterFragment frag = new FlutterFragment();
......@@ -144,7 +158,8 @@ public class FlutterFragment extends Fragment {
initialRoute,
appBundlePath,
shellArgs,
renderMode
renderMode,
transparencyMode
);
frag.setArguments(args);
......@@ -194,7 +209,8 @@ public class FlutterFragment extends Fragment {
@Nullable String initialRoute,
@Nullable String appBundlePath,
@Nullable FlutterShellArgs flutterShellArgs,
@Nullable FlutterView.RenderMode renderMode) {
@Nullable FlutterView.RenderMode renderMode,
@Nullable FlutterView.TransparencyMode transparencyMode) {
Bundle args = new Bundle();
args.putString(ARG_INITIAL_ROUTE, initialRoute);
args.putString(ARG_APP_BUNDLE_PATH, appBundlePath);
......@@ -204,6 +220,7 @@ public class FlutterFragment extends Fragment {
args.putStringArray(ARG_FLUTTER_INITIALIZATION_ARGS, flutterShellArgs.toArray());
}
args.putString(ARG_FLUTTERVIEW_RENDER_MODE, renderMode != null ? renderMode.name() : FlutterView.RenderMode.surface.name());
args.putString(ARG_FLUTTERVIEW_TRANSPARENCY_MODE, transparencyMode != null ? transparencyMode.name() : FlutterView.TransparencyMode.transparent.name());
return args;
}
......@@ -315,7 +332,7 @@ public class FlutterFragment extends Fragment {
@Nullable
@Override
public View onCreateView(LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) {
flutterView = new FlutterView(getContext(), getRenderMode());
flutterView = new FlutterView(getContext(), getRenderMode(), getTransparencyMode());
flutterView.addOnFirstFrameRenderedListener(onFirstFrameRenderedListener);
// We post() the code that attaches the FlutterEngine to our FlutterView because there is
......@@ -413,6 +430,18 @@ public class FlutterFragment extends Fragment {
return FlutterView.RenderMode.valueOf(renderModeName);
}
/**
* Returns the desired {@link FlutterView.TransparencyMode} for the {@link FlutterView} displayed in
* this {@code FlutterFragment}.
* <p>
* Defaults to {@link FlutterView.TransparencyMode#transparent}.
*/
@NonNull
protected FlutterView.TransparencyMode getTransparencyMode() {
String transparencyModeName = getArguments().getString(ARG_FLUTTERVIEW_TRANSPARENCY_MODE, FlutterView.TransparencyMode.transparent.name());
return FlutterView.TransparencyMode.valueOf(transparencyModeName);
}
// TODO(mattcarroll): determine why this can't be in onResume(). Comment reason, or move if possible.
public void onPostResume() {
Log.d(TAG, "onPostResume()");
......
......@@ -5,6 +5,7 @@
package io.flutter.embedding.android;
import android.content.Context;
import android.graphics.PixelFormat;
import android.support.annotation.NonNull;
import android.support.annotation.Nullable;
import android.util.AttributeSet;
......@@ -36,6 +37,7 @@ import io.flutter.embedding.engine.renderer.OnFirstFrameRenderedListener;
public class FlutterSurfaceView extends SurfaceView implements FlutterRenderer.RenderSurface {
private static final String TAG = "FlutterSurfaceView";
private final boolean renderTransparently;
private boolean isSurfaceAvailableForRendering = false;
private boolean isAttachedToFlutterRenderer = false;
@Nullable
......@@ -80,19 +82,39 @@ public class FlutterSurfaceView extends SurfaceView implements FlutterRenderer.R
/**
* Constructs a {@code FlutterSurfaceView} programmatically, without any XML attributes.
*/
public FlutterSurfaceView(Context context) {
this(context, null);
public FlutterSurfaceView(@NonNull Context context) {
this(context, null, false);
}
/**
* Constructs a {@code FlutterSurfaceView} programmatically, without any XML attributes, and
* with control over whether or not this {@code FlutterSurfaceView} renders with transparency.
*/
public FlutterSurfaceView(@NonNull Context context, boolean renderTransparently) {
this(context, null, renderTransparently);
}
/**
* Constructs a {@code FlutterSurfaceView} in an XML-inflation-compliant manner.
*/
public FlutterSurfaceView(Context context, AttributeSet attrs) {
public FlutterSurfaceView(@NonNull Context context, @NonNull AttributeSet attrs) {
this(context, attrs, false);
}
private FlutterSurfaceView(@NonNull Context context, @Nullable AttributeSet attrs, boolean renderTransparently) {
super(context, attrs);
this.renderTransparently = renderTransparently;
init();
}
private void init() {
// If transparency is desired then we'll enable a transparent pixel format and place
// our Window above everything else to get transparent background rendering.
if (renderTransparently) {
getHolder().setFormat(PixelFormat.TRANSPARENT);
setZOrderOnTop(true);
}
// Grab a reference to our underlying Surface and register callbacks with that Surface so we
// can monitor changes and forward those changes on to native Flutter code.
getHolder().addCallback(surfaceCallback);
......
......@@ -62,6 +62,8 @@ public class FlutterView extends FrameLayout {
// Behavior configuration of this FlutterView.
@NonNull
private RenderMode renderMode;
@Nullable
private TransparencyMode transparencyMode;
// Internal view hierarchy references.
@Nullable
......@@ -96,20 +98,41 @@ public class FlutterView extends FrameLayout {
};
/**
* Constructs a {@code FlutterSurfaceView} programmatically, without any XML attributes.
*
* {@link #renderMode} defaults to {@link RenderMode#surface}.
* Constructs a {@code FlutterView} programmatically, without any XML attributes.
* <p>
* <ul>
* <li>{@link #renderMode} defaults to {@link RenderMode#surface}.</li>
* <li>{@link #transparencyMode} defaults to {@link TransparencyMode#opaque}.</li>
* </ul>
*/
public FlutterView(@NonNull Context context) {
this(context, null, null);
this(context, null, null, null);
}
/**
* Constructs a {@code FlutterSurfaceView} programmatically, without any XML attributes,
* Constructs a {@code FlutterView} programmatically, without any XML attributes,
* and allows selection of a {@link #renderMode}.
* <p>
* {@link #transparencyMode} defaults to {@link TransparencyMode#opaque}.
*/
public FlutterView(@NonNull Context context, @NonNull RenderMode renderMode) {
this(context, null, renderMode);
this(context, null, renderMode, null);
}
/**
* Constructs a {@code FlutterView} programmatically, without any XML attributes,
* assumes the use of {@link RenderMode#surface}, and allows selection of a {@link #transparencyMode}.
*/
public FlutterView(@NonNull Context context, @NonNull TransparencyMode transparencyMode) {
this(context, null, RenderMode.surface, transparencyMode);
}
/**
* Constructs a {@code FlutterView} programmatically, without any XML attributes, and allows
* a selection of {@link #renderMode} and {@link #transparencyMode}.
*/
public FlutterView(@NonNull Context context, @NonNull RenderMode renderMode, @NonNull TransparencyMode transparencyMode) {
this(context, null, renderMode, transparencyMode);
}
/**
......@@ -118,13 +141,14 @@ public class FlutterView extends FrameLayout {
* // TODO(mattcarroll): expose renderMode in XML when build system supports R.attr
*/
public FlutterView(@NonNull Context context, @Nullable AttributeSet attrs) {
this(context, attrs, null);
this(context, attrs, null, null);
}
private FlutterView(@NonNull Context context, @Nullable AttributeSet attrs, @Nullable RenderMode renderMode) {
private FlutterView(@NonNull Context context, @Nullable AttributeSet attrs, @Nullable RenderMode renderMode, @Nullable TransparencyMode transparencyMode) {
super(context, attrs);
this.renderMode = renderMode == null ? RenderMode.surface : renderMode;
this.transparencyMode = transparencyMode != null ? transparencyMode : TransparencyMode.opaque;
init();
}
......@@ -135,7 +159,7 @@ public class FlutterView extends FrameLayout {
switch (renderMode) {
case surface:
Log.d(TAG, "Internally creating a FlutterSurfaceView.");
FlutterSurfaceView flutterSurfaceView = new FlutterSurfaceView(getContext());
FlutterSurfaceView flutterSurfaceView = new FlutterSurfaceView(getContext(), transparencyMode == TransparencyMode.transparent);
renderSurface = flutterSurfaceView;
addView(flutterSurfaceView);
break;
......@@ -591,4 +615,39 @@ public class FlutterView extends FrameLayout {
*/
texture
}
/**
* Transparency mode for a {@code FlutterView}.
* <p>
* {@code TransparencyMode} impacts the visual behavior and performance of a {@link FlutterSurfaceView},
* which is displayed when a {@code FlutterView} uses {@link RenderMode#surface}.
* <p>
* {@code TransparencyMode} does not impact {@link FlutterTextureView}, which is displayed when
* a {@code FlutterView} uses {@link RenderMode#texture}, because a {@link FlutterTextureView}
* automatically comes with transparency.
*/
public enum TransparencyMode {
/**
* Renders a {@code FlutterView} without any transparency. This affects {@code FlutterView}s in
* {@link RenderMode#surface} by introducing a base color of black, and places the
* {@link FlutterSurfaceView}'s {@code Window} behind all other content.
* <p>
* In {@link RenderMode#surface}, this mode is the most performant and is a good choice for
* fullscreen Flutter UIs that will not undergo {@code Fragment} transactions. If this mode is
* used within a {@code Fragment}, and that {@code Fragment} is replaced by another one, a
* brief black flicker may be visible during the switch.
*/
opaque,
/**
* Renders a {@code FlutterView} with transparency. This affects {@code FlutterView}s in
* {@link RenderMode#surface} by allowing background transparency, and places the
* {@link FlutterSurfaceView}'s {@code Window} on top of all other content.
* <p>
* In {@link RenderMode#surface}, this mode is less performant than {@link #opaque}, but this
* mode avoids the black flicker problem that {@link #opaque} has when going through
* {@code Fragment} transactions. Consider using this {@code TransparencyMode} if you intend to
* switch {@code Fragment}s at runtime that contain a Flutter UI.
*/
transparent
}
}
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册