未验证 提交 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 ...@@ -273,6 +273,7 @@ public class FlutterActivity extends FragmentActivity implements OnFirstFrameRen
.appBundlePath(getAppBundlePath()) .appBundlePath(getAppBundlePath())
.flutterShellArgs(FlutterShellArgs.fromIntent(getIntent())) .flutterShellArgs(FlutterShellArgs.fromIntent(getIntent()))
.renderMode(FlutterView.RenderMode.surface) .renderMode(FlutterView.RenderMode.surface)
.transparencyMode(FlutterView.TransparencyMode.opaque)
.build(); .build();
} }
......
...@@ -65,6 +65,7 @@ public class FlutterFragment extends Fragment { ...@@ -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_APP_BUNDLE_PATH = "app_bundle_path";
private static final String ARG_FLUTTER_INITIALIZATION_ARGS = "initialization_args"; 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_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 * Builder that creates a new {@code FlutterFragment} with {@code arguments} that correspond
...@@ -82,6 +83,7 @@ public class FlutterFragment extends Fragment { ...@@ -82,6 +83,7 @@ public class FlutterFragment extends Fragment {
private String appBundlePath = null; private String appBundlePath = null;
private FlutterShellArgs shellArgs = null; private FlutterShellArgs shellArgs = null;
private FlutterView.RenderMode renderMode = FlutterView.RenderMode.surface; 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". * The name of the initial Dart method to invoke, defaults to "main".
...@@ -135,6 +137,18 @@ public class FlutterFragment extends Fragment { ...@@ -135,6 +137,18 @@ public class FlutterFragment extends Fragment {
return this; 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 @NonNull
public FlutterFragment build() { public FlutterFragment build() {
FlutterFragment frag = new FlutterFragment(); FlutterFragment frag = new FlutterFragment();
...@@ -144,7 +158,8 @@ public class FlutterFragment extends Fragment { ...@@ -144,7 +158,8 @@ public class FlutterFragment extends Fragment {
initialRoute, initialRoute,
appBundlePath, appBundlePath,
shellArgs, shellArgs,
renderMode renderMode,
transparencyMode
); );
frag.setArguments(args); frag.setArguments(args);
...@@ -194,7 +209,8 @@ public class FlutterFragment extends Fragment { ...@@ -194,7 +209,8 @@ public class FlutterFragment extends Fragment {
@Nullable String initialRoute, @Nullable String initialRoute,
@Nullable String appBundlePath, @Nullable String appBundlePath,
@Nullable FlutterShellArgs flutterShellArgs, @Nullable FlutterShellArgs flutterShellArgs,
@Nullable FlutterView.RenderMode renderMode) { @Nullable FlutterView.RenderMode renderMode,
@Nullable FlutterView.TransparencyMode transparencyMode) {
Bundle args = new Bundle(); Bundle args = new Bundle();
args.putString(ARG_INITIAL_ROUTE, initialRoute); args.putString(ARG_INITIAL_ROUTE, initialRoute);
args.putString(ARG_APP_BUNDLE_PATH, appBundlePath); args.putString(ARG_APP_BUNDLE_PATH, appBundlePath);
...@@ -204,6 +220,7 @@ public class FlutterFragment extends Fragment { ...@@ -204,6 +220,7 @@ public class FlutterFragment extends Fragment {
args.putStringArray(ARG_FLUTTER_INITIALIZATION_ARGS, flutterShellArgs.toArray()); 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_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; return args;
} }
...@@ -315,7 +332,7 @@ public class FlutterFragment extends Fragment { ...@@ -315,7 +332,7 @@ public class FlutterFragment extends Fragment {
@Nullable @Nullable
@Override @Override
public View onCreateView(LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) { 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); flutterView.addOnFirstFrameRenderedListener(onFirstFrameRenderedListener);
// We post() the code that attaches the FlutterEngine to our FlutterView because there is // We post() the code that attaches the FlutterEngine to our FlutterView because there is
...@@ -413,6 +430,18 @@ public class FlutterFragment extends Fragment { ...@@ -413,6 +430,18 @@ public class FlutterFragment extends Fragment {
return FlutterView.RenderMode.valueOf(renderModeName); 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. // TODO(mattcarroll): determine why this can't be in onResume(). Comment reason, or move if possible.
public void onPostResume() { public void onPostResume() {
Log.d(TAG, "onPostResume()"); Log.d(TAG, "onPostResume()");
......
...@@ -5,6 +5,7 @@ ...@@ -5,6 +5,7 @@
package io.flutter.embedding.android; package io.flutter.embedding.android;
import android.content.Context; import android.content.Context;
import android.graphics.PixelFormat;
import android.support.annotation.NonNull; import android.support.annotation.NonNull;
import android.support.annotation.Nullable; import android.support.annotation.Nullable;
import android.util.AttributeSet; import android.util.AttributeSet;
...@@ -36,6 +37,7 @@ import io.flutter.embedding.engine.renderer.OnFirstFrameRenderedListener; ...@@ -36,6 +37,7 @@ import io.flutter.embedding.engine.renderer.OnFirstFrameRenderedListener;
public class FlutterSurfaceView extends SurfaceView implements FlutterRenderer.RenderSurface { public class FlutterSurfaceView extends SurfaceView implements FlutterRenderer.RenderSurface {
private static final String TAG = "FlutterSurfaceView"; private static final String TAG = "FlutterSurfaceView";
private final boolean renderTransparently;
private boolean isSurfaceAvailableForRendering = false; private boolean isSurfaceAvailableForRendering = false;
private boolean isAttachedToFlutterRenderer = false; private boolean isAttachedToFlutterRenderer = false;
@Nullable @Nullable
...@@ -80,19 +82,39 @@ public class FlutterSurfaceView extends SurfaceView implements FlutterRenderer.R ...@@ -80,19 +82,39 @@ public class FlutterSurfaceView extends SurfaceView implements FlutterRenderer.R
/** /**
* Constructs a {@code FlutterSurfaceView} programmatically, without any XML attributes. * Constructs a {@code FlutterSurfaceView} programmatically, without any XML attributes.
*/ */
public FlutterSurfaceView(Context context) { public FlutterSurfaceView(@NonNull Context context) {
this(context, null); 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. * 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); super(context, attrs);
this.renderTransparently = renderTransparently;
init(); init();
} }
private void 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 // 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. // can monitor changes and forward those changes on to native Flutter code.
getHolder().addCallback(surfaceCallback); getHolder().addCallback(surfaceCallback);
......
...@@ -62,6 +62,8 @@ public class FlutterView extends FrameLayout { ...@@ -62,6 +62,8 @@ public class FlutterView extends FrameLayout {
// Behavior configuration of this FlutterView. // Behavior configuration of this FlutterView.
@NonNull @NonNull
private RenderMode renderMode; private RenderMode renderMode;
@Nullable
private TransparencyMode transparencyMode;
// Internal view hierarchy references. // Internal view hierarchy references.
@Nullable @Nullable
...@@ -96,20 +98,41 @@ public class FlutterView extends FrameLayout { ...@@ -96,20 +98,41 @@ public class FlutterView extends FrameLayout {
}; };
/** /**
* Constructs a {@code FlutterSurfaceView} programmatically, without any XML attributes. * Constructs a {@code FlutterView} programmatically, without any XML attributes.
* * <p>
* {@link #renderMode} defaults to {@link RenderMode#surface}. * <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) { 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}. * and allows selection of a {@link #renderMode}.
* <p>
* {@link #transparencyMode} defaults to {@link TransparencyMode#opaque}.
*/ */
public FlutterView(@NonNull Context context, @NonNull RenderMode renderMode) { 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 { ...@@ -118,13 +141,14 @@ public class FlutterView extends FrameLayout {
* // TODO(mattcarroll): expose renderMode in XML when build system supports R.attr * // TODO(mattcarroll): expose renderMode in XML when build system supports R.attr
*/ */
public FlutterView(@NonNull Context context, @Nullable AttributeSet attrs) { 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); super(context, attrs);
this.renderMode = renderMode == null ? RenderMode.surface : renderMode; this.renderMode = renderMode == null ? RenderMode.surface : renderMode;
this.transparencyMode = transparencyMode != null ? transparencyMode : TransparencyMode.opaque;
init(); init();
} }
...@@ -135,7 +159,7 @@ public class FlutterView extends FrameLayout { ...@@ -135,7 +159,7 @@ public class FlutterView extends FrameLayout {
switch (renderMode) { switch (renderMode) {
case surface: case surface:
Log.d(TAG, "Internally creating a FlutterSurfaceView."); Log.d(TAG, "Internally creating a FlutterSurfaceView.");
FlutterSurfaceView flutterSurfaceView = new FlutterSurfaceView(getContext()); FlutterSurfaceView flutterSurfaceView = new FlutterSurfaceView(getContext(), transparencyMode == TransparencyMode.transparent);
renderSurface = flutterSurfaceView; renderSurface = flutterSurfaceView;
addView(flutterSurfaceView); addView(flutterSurfaceView);
break; break;
...@@ -591,4 +615,39 @@ public class FlutterView extends FrameLayout { ...@@ -591,4 +615,39 @@ public class FlutterView extends FrameLayout {
*/ */
texture 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.
先完成此消息的编辑!
想要评论请 注册