Skip to content

Android PlatformViews page back to non-platformview page, still glitch for one frame after this fix: https://github.com/flutter/engine/pull/30724/ #102508

Closed
@eggfly

Description

@eggfly

Steps to Reproduce

Friendly cc @blasten 😄

  1. Use the commits after this fix: Remove glitch when displaying platform views engine#30724
  2. Use the stable 2.10.3 engine version, or use the github.com/flutter/flutter master branch commit(a1a305c), it's exactly before "Roll Engine" commit before the new android platform view architecture merged into main engine branch(the new arch is ok without bug😄): flutter/engine@5f0271a:
  1. Use the demo Dart code below:
  2. Click any of the button in the list, navigate to webview and go back, you can see one frame glitch (about 30% probability), which position is around the clicked button's gray background.

Screenrecord
By camera:

IMG_0176.MOV

By adb screen record:

video.mp4

Screenshot:
image

Demo code:

CupertinoPageRoute Demo
import 'package:flutter/material.dart';
import 'package:flutter/cupertino.dart';

import 'package:webview_flutter/webview_flutter.dart';


void main() {
  WebView.platform = SurfaceAndroidWebView();
  runApp(MyApp());
}

class MyApp extends StatelessWidget {
  const MyApp({Key? key}) : super(key: key);

  @override
  Widget build(BuildContext context) {
    return const MaterialApp(home: HomeScreen());
  }
}

class HomeScreen extends StatefulWidget {
  const HomeScreen({Key? key}) : super(key: key);

  @override
  _HomeScreenState createState() => _HomeScreenState();
}

class _HomeScreenState extends State<HomeScreen> {
  @override
  Widget build(BuildContext context) {
    return Scaffold(
      body: SafeArea(
        child: Column(
          children: [
            ListTile(
              title: Text('Red'),
              onTap: () {
                Navigator.push(context, CupertinoPageRoute(builder: (context) {
                  return const ProducDetailPage();
                }));
              },
            ),
            ListTile(
              title: Text('Green'),
              onTap: () {
                Navigator.push(context, CupertinoPageRoute(builder: (context) {
                  return const ProducDetailPage();
                }));
              },
            ),
            ListTile(
              title: Text('Green 1'),
              onTap: () {
                Navigator.push(context, CupertinoPageRoute(builder: (context) {
                  return const ProducDetailPage();
                }));
              },
            ),
            ListTile(
              title: Text('Green 2'),
              onTap: () {
                Navigator.push(context, CupertinoPageRoute(builder: (context) {
                  return const ProducDetailPage();
                }));
              },
            ),
            ListTile(
              title: Text('Green 3'),
              onTap: () {
                Navigator.push(context, CupertinoPageRoute(builder: (context) {
                  return const ProducDetailPage();
                }));
              },
            ),
            ListTile(
              title: Text('Green 2'),
              onTap: () {
                Navigator.push(context, CupertinoPageRoute(builder: (context) {
                  return const ProducDetailPage();
                }));
              },
            ),
            ListTile(
              title: Text('Green 2'),
              onTap: () {
                Navigator.push(context, CupertinoPageRoute(builder: (context) {
                  return const ProducDetailPage();
                }));
              },
            ),
            ListTile(
              title: Text('Green 2'),
              onTap: () {
                Navigator.push(context, CupertinoPageRoute(builder: (context) {
                  return const ProducDetailPage();
                }));
              },
            ),
            ListTile(
              title: Text('Green 2'),
              onTap: () {
                Navigator.push(context, CupertinoPageRoute(builder: (context) {
                  return const ProducDetailPage();
                }));
              },
            ),
            ListTile(
              title: Text('Green 2'),
              onTap: () {
                Navigator.push(context, CupertinoPageRoute(builder: (context) {
                  return const ProducDetailPage();
                }));
              },
            ),
            ListTile(
              title: Text('Green 2'),
              onTap: () {
                Navigator.push(context, CupertinoPageRoute(builder: (context) {
                  return const ProducDetailPage();
                }));
              },
            ),
            CircularProgressIndicator(
              semanticsLabel: 'Linear progress indicator',
            ),
            CircularProgressIndicator(
              semanticsLabel: 'Linear progress indicator',
            ),
            CircularProgressIndicator(
              semanticsLabel: 'Linear progress indicator',
            ),
            CircularProgressIndicator(
              semanticsLabel: 'Linear progress indicator',
            ),
            CircularProgressIndicator(
              semanticsLabel: 'Linear progress indicator',
            ),
            ListTile(
              title: Text('Green 2'),
              onTap: () {
                Navigator.push(context, MaterialPageRoute(builder: (context) {
                  return const ProducDetailPage();
                }));
              },
            ),
            ListTile(
              title: Text('Green 2'),
              onTap: () {
                Navigator.push(context, MaterialPageRoute(builder: (context) {
                  return const ProducDetailPage();
                }));
              },
            ),
            ListTile(
              title: Text('Green 2'),
              onTap: () {
                Navigator.push(context, MaterialPageRoute(builder: (context) {
                  return const ProducDetailPage();
                }));
              },
            ),
            ListTile(
              title: Text('Green 2'),
              onTap: () {
                Navigator.push(context, MaterialPageRoute(builder: (context) {
                  return const ProducDetailPage();
                }));
              },
            ),
            ListTile(
              title: Text('Green 2'),
              onTap: () {
                Navigator.push(context, MaterialPageRoute(builder: (context) {
                  return const ProducDetailPage();
                }));
              },
            ),
            ListTile(
              title: Text('Green 2'),
              onTap: () {
                Navigator.push(context, MaterialPageRoute(builder: (context) {
                  return const ProducDetailPage();
                }));
              },
            ),
            ListTile(
              title: Text('Green 2'),
              onTap: () {
                Navigator.push(context, MaterialPageRoute(builder: (context) {
                  return const ProducDetailPage();
                }));
              },
            ),
            // CircularProgressIndicator(
            //   semanticsLabel: 'Linear progress indicator',
            // ),
            // SizedBox(
            //   height: 150,
            //   child: WebView(
            //     initialUrl: 'https://flutter.dev',
            //   ),
            // ),
          ],
        ),
      ),
    );
  }
}

class ProducDetailPage extends StatelessWidget {
  const ProducDetailPage({Key? key}) : super(key: key);

  @override
  Widget build(BuildContext context) {
    return Scaffold(
        appBar: AppBar(
          title: const Text('Produc Detail'),
        ),
        body: Column(children: const [
          Padding(
            padding: EdgeInsets.all(8.0),
            child: SizedBox(
              height: 150,
              child: Placeholder(
                color: Colors.red,
              ),
            ),
          ),
          SizedBox(
            height: 150,
            child: WebView(
              initialUrl: 'https://flutter.dev',
            ),
          ),
            CircularProgressIndicator(
              semanticsLabel: 'Linear progress indicator',
            ),
        ]));
  }
}

class ProductDetailPage2 extends StatelessWidget {
  const ProductDetailPage2({Key? key}) : super(key: key);

  @override
  Widget build(BuildContext context) {
    return Scaffold(
        appBar: AppBar(
          title: const Text('Produc Detail'),
        ),
        body: Column(children: const [
          SizedBox(
            height: 150,
            child: Placeholder(
              color: Colors.green,
            ),
          ),
        ]));
  }
}

Here's my diagnosis:

Firstly, the commit https://github.com/flutter/engine/pull/30724/files#diff-87fa95e503a7a95a32aee115dded76fc6f8ec76fc29c2d2c071b413df0c3a096R265
introduced the isPaused member, when isPaused is set to true, then the stopRenderingToSurface() is not called any more:
https://github.com/flutter/engine/pull/30724/files#diff-d3ae30246a95a9e78606b57b860941c4d74d5dfba9ecc394f202c9a62002531bR242

image

Let's see there's a variable named isDisplayingFlutterUi in FlutterRenderer.java :

https://github.com/flutter/engine/blob/f6dd681d4ec88b86a80bd367e6e050ae4ef7ffc7/shell/platform/android/io/flutter/embedding/engine/renderer/FlutterRenderer.java#L44

It controls the logic in addIsDisplayingFlutterUiListener()

image

https://github.com/flutter/engine/blob/f6dd681d4ec88b86a80bd367e6e050ae4ef7ffc7/shell/platform/android/io/flutter/embedding/engine/renderer/FlutterRenderer.java#L78

when isDisplayingFlutterUi is true, the addIsDisplayingFlutterUiListener will directly calls the listener on current java call stack.

But in this issue's scenario, the code in RevertImageView():

  • firstly calls renderSurface.attachToRenderer(renderer); but not set isDisplayingFlutterUi to false;
  • secondly calls addIsDisplayingFlutterUiListener and run onDone.run() directly on current stack.
    It will
    onDone.run() will call finishFrame() and will set overlayView.setVisibility(View.GONE);:

image

image

But the gone of FlutterImageView is too early! And I think the first new frame rendering on SurfaceView is not ready yet. The previous image of SurfaceView shows the click state (with a gray shadow) of the button..

I think the wrong stack is here:
image

After revert this commit, the original right stack is below:

image

Metadata

Metadata

Assignees

No one assigned

    Labels

    a: platform-viewsEmbedding Android/iOS views in Flutter appsengineflutter/engine repository. See also e: labels.platform-androidAndroid applications specifically

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions