Repository: flutter
Issue: [Android] FlutterView.revertImageView() problems
Labels: platform-android,a: platform-views,has reproducible steps,P2,team-android,triaged-android,found in release: 3.13,found in release: 3.14

### Is there an existing issue for this?

- [X] I have searched the [existing issues](https://github.com/flutter/flutter/issues)
- [X] I have read the [guide to filing a bug](https://flutter.dev/docs/resources/bug-reports)

### Steps to reproduce

Run code, click button

### Expected results

Between step 4 and step 1, step 3 should not visible

### Actual results

When changing from step 4 to step 1, step 3 is visible for 1 frame.
Because the former surface is displaying step 3.
The current code set the former surface visible immediately instead of waiting for the new frame.

### Code sample

<details><summary>Code sample</summary>

```dart


import 'package:flutter/material.dart';
import 'package:google_maps_flutter/google_maps_flutter.dart';

class Test extends StatefulWidget {
  const Test({super.key});

  @override
  State<Test> createState() => _TestState();
}

class _TestState extends State<Test> {
  int step = 1;

  static const CameraPosition _kGooglePlex = CameraPosition(
    target: LatLng(37.42796133580664, -122.085749655962),
    zoom: 14.4746,
  );

  start() async {
    setState(() {
      step = 2;
    });
    await Future.delayed(Duration(seconds: 2));
    setState(() {
      step = 3;
    });
    await Future.delayed(Duration(seconds: 2));
    setState(() {
      step = 4;
    });
    await Future.delayed(Duration(seconds: 2));
    setState(() {
      step = 1;
    });
  }

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      floatingActionButton: FloatingActionButton(
        onPressed: () {
          start();
        },
      ),
      backgroundColor: getBg(),
      body: Column(
        children: [
          if (step == 1) Stack(children: List.generate(900, (index) => FlutterLogo(size: 40,)),),
          SizedBox(height: 50,),
          Text(" STEP $step", style: TextStyle(fontWeight: FontWeight.w800, color: Colors.deepOrange, fontSize: 25),),
          SizedBox(height: 100,),
          if (step == 3 || step == 4) SizedBox(
            width: 200,
            height: 200,
            child: GoogleMap(
              initialCameraPosition: _kGooglePlex,
              onMapCreated: (GoogleMapController controller) {
              },
            ),
          ),
        ],
      ),
    );
  }

  Color getBg() {
    switch(step) {
      case 1:
        return Colors.white;
      case 2:
        return Colors.red;
      case 3:
        return Colors.blue;
      case 4:
        return Colors.white;
    }
    return Colors.brown;
  }
}

```

</details>

### Screenshots or Video

<details>
<summary>Screenshots / Video demonstration</summary>

https://github.com/flutter/flutter/assets/26743089/e6f31c0e-a2d4-428d-8102-8cfbd61a1cb8

</details>

### Flutter Doctor output

<details><summary>Doctor output</summary>

```console

flutter doctor --verbose
[!] Flutter (Channel master, 3.14.0-14.0.pre.167, on macOS 13.0.1 22A400 darwin-x64, locale en-VN)
    • Flutter version 3.14.0-14.0.pre.167 on channel master at /Users/xuantung/Desktop/Develop/flutter/master/flutter
    ! Warning: `flutter` on your path resolves to /Users/xuantung/Desktop/Develop/flutter/3.3.10/flutter/bin/flutter, which is not inside your current Flutter SDK checkout at /Users/xuantung/Desktop/Develop/flutter/master/flutter. Consider adding /Users/xuantung/Desktop/Develop/flutter/master/flutter/bin to the front of your path.
    ! Warning: `dart` on your path resolves to /Users/xuantung/Desktop/Develop/flutter/3.3.10/flutter/bin/dart, which is not inside your current Flutter SDK checkout at /Users/xuantung/Desktop/Develop/flutter/master/flutter. Consider adding /Users/xuantung/Desktop/Develop/flutter/master/flutter/bin to the front of your path.
    • Upstream repository https://github.com/flutter/flutter.git
    • Framework revision 7cbaa2a41e (6 hours ago), 2023-09-07 21:29:29 -0400
    • Engine revision df3965a55f
    • Dart version 3.2.0 (build 3.2.0-134.0.dev)
    • DevTools version 2.27.0
    • If those were intentional, you can disregard the above warnings; however it is recommended to use "git" directly to perform update checks and upgrades.

[!] Android toolchain - develop for Android devices (Android SDK version 33.0.2)
    • Android SDK at /Users/xuantung/Library/Android/sdk
    ✗ cmdline-tools componen

t is missing
      Run `path/to/sdkmanager --install "cmdline-tools;latest"`
      See https://developer.android.com/studio/command-line for more details.
    ✗ Android license status unknown.
      Run `flutter doctor --android-licenses` to accept the SDK licenses.
      See https://flutter.dev/docs/get-started/install/macos#android-setup for more details.

[✓] Xcode - develop for iOS and macOS (Xcode 14.3.1)
    • Xcode at /Applications/Xcode.app/Contents/Developer
    • Build 14E300c
    • CocoaPods version 1.12.1

[✓] Chrome - develop for the web
    • Chrome at /Applications/Google Chrome.app/Contents/MacOS/Google Chrome

[✓] Android Studio (version 2022.3)
    • Android Studio at /Applications/Android Studio.app/Contents
    • Flutter plugin can be installed from:
      🔨 https://plugins.jetbrains.com/plugin/9212-flutter
    • Dart plugin can be installed from:
      🔨 https://plugins.jetbrains.com/plugin/6351-dart
    • Java version OpenJDK Runtime Environment (build 17.0.6+0-17.0.6b829.9-10027231)

[✓] VS Code (version 1.81.1)
    • VS Code at /Applications/Visual Studio Code.app/Contents
    • Flutter extension can be installed from:
      🔨 https://marketplace.visualstudio.com/items?itemName=Dart-Code.flutter

[✓] Connected device (3 available)
    • SM A235F (mobile) • R58W2095NQK • android-arm64  • Android 13 (API 33)
    • macOS (desktop)   • macos       • darwin-x64     • macOS 13.0.1 22A400 darwin-x64
    • Chrome (web)      • chrome      • web-javascript • Google Chrome 116.0.5845.179

[✓] Network resources
    • All expected network resources are available.

! Doctor found issues in 2 categories.
```

</details>


### Use case

About this method in FlutterView.java

``` java
  public void revertImageView(@NonNull Runnable onDone) {
    if (flutterImageView == null) {
      Log.v(TAG, "Tried to revert the image view, but no image view is used.");
      return;
    }
    if (previousRenderSurface == null) {
      Log.v(TAG, "Tried to revert the image view, but no previous surface was used.");
      return;
    }
    renderSurface = previousRenderSurface;
    previousRenderSurface = null;

    final FlutterRenderer renderer = flutterEngine.getRenderer();

    if (flutterEngine == null || renderer == null) {
      flutterImageView.detachFromRenderer();
      releaseImageView();
      onDone.run();
      return;
    }
    // Start rendering on the previous surface.
    // This surface is typically `FlutterSurfaceView` or `FlutterTextureView`.
    renderSurface.attachToRenderer(renderer);

    // Install a Flutter UI listener to wait until the first frame is rendered
    // in the new surface to call the `onDone` callback.
    renderer.addIsDisplayingFlutterUiListener(
        new FlutterUiDisplayListener() {
          @Override
          public void onFlutterUiDisplayed() {
            renderer.removeIsDisplayingFlutterUiListener(this);
            onDone.run();
            if (!(renderSurface instanceof FlutterImageView) && flutterImageView != null) {
              flutterImageView.detachFromRenderer();
              releaseImageView();
            }
          }

          @Override
          public void onFlutterUiNoLongerDisplayed() {
            // no-op
          }
        });
  }
```

The `FlutterUiDisplayListener.onFlutterUiDisplayed()` will run immediately because `FlutterRenderer.isDisplayingFlutterUi = true`.
This will hide the FlutterImageView and show FlutterSurfaceView immediately which is against the original purpose of the author?

```
    // Install a Flutter UI listener to wait until the first frame is rendered
    // in the new surface to call the `onDone` callback.
```

The FlutterSurfaceView should be shown only when the newest image is visible.

### Proposal

Should it call `renderer.stopRenderingToSurface();` before starting to render on the new surface?

Update: If add the above code and switch back and forth quickly, flutterImageView becomes freeze.