Skip to content

Blank screen when adding a FlutterView for the second time to ViewGroup on Android #32624

@chip2n

Description

@chip2n

It seems that FlutterView does not render properly when it is added for the second time to a ViewGroup (in our case when Conductor controllers are detached and later attached again). This also happens when the parent container is removed from the hierarchy and later added again. We can work around this by recreating the FlutterView each time this happens, but that doesn't seem like a good permanent solution.

Steps to reproduce

  1. Create a FlutterView and attach it to the FlutterEngine
  2. Add the FlutterView to a container
  3. Remove the FlutterView from the container
  4. Add the FlutterView to the container again

The second time the FlutterView is added, there's nothing rendered. In some cases we've also seen a black screen.

Here's some Android code to reproduce this issue - in this case an activity containing a FrameLayout and a button. Pressing the button adds the FlutterView to the container if it isn't there already, otherwise it removes the view from the container.

import android.os.Bundle
import androidx.appcompat.app.AppCompatActivity
import io.flutter.embedding.android.FlutterView
import io.flutter.embedding.engine.FlutterEngine
import io.flutter.embedding.engine.FlutterShellArgs
import io.flutter.embedding.engine.dart.DartExecutor
import io.flutter.facade.Flutter
import io.flutter.view.FlutterMain
import kotlinx.android.synthetic.main.activity_main.*

class MainActivity : AppCompatActivity() {

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_main)

        Flutter.startInitialization(applicationContext)
        val shellArgs = FlutterShellArgs(arrayOf<String>())
        FlutterMain.ensureInitializationComplete(applicationContext, shellArgs.toArray())

        val engine = FlutterEngine(this).apply {
            navigationChannel.setInitialRoute("/")
            val appBundlePath = FlutterMain.findAppBundlePath(applicationContext)
            val entrypoint = DartExecutor.DartEntrypoint(resources.assets, appBundlePath, "main")
            dartExecutor.executeDartEntrypoint(entrypoint)
        }

        val flutterView = FlutterView(this, FlutterView.RenderMode.texture).apply {
            attachToFlutterEngine(engine)
        }

        button.setOnClickListener {
            if (flutterContainer.childCount == 0) {
                flutterContainer.addView(flutterView)
            } else {
                flutterContainer.removeView(flutterView)
            }
        }
    }
}
<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    android:layout_width="match_parent"
    android:layout_height="match_parent">

    <Button
        android:id="@+id/button"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="Press me"
        app:layout_constraintBottom_toBottomOf="parent"
        app:layout_constraintEnd_toEndOf="parent"
        app:layout_constraintStart_toStartOf="parent"
        app:layout_constraintTop_toTopOf="parent" />

    <FrameLayout
        android:id="@+id/flutterContainer"
        android:layout_width="match_parent"
        android:layout_height="match_parent" />

</androidx.constraintlayout.widget.ConstraintLayout>

Logs

Here's the flutter doctor output:

[✓] Flutter (Channel master, v1.5.9-pre.223, on Linux, locale en_US.UTF-8)
    • Flutter version 1.5.9-pre.223 at /home/chip/flutter
    • Framework revision b76a1e8312 (6 hours ago), 2019-05-13 09:06:30 +0100
    • Engine revision 816d3fc586
    • Dart version 2.3.1 (build 2.3.1-dev.0.0 a0290f823c)

[✓] Android toolchain - develop for Android devices (Android SDK version 28.0.3)
    • Android SDK at /home/chip/android/sdk
    • Android NDK location not configured (optional; useful for native profiling
      support)
    • Platform android-28, build-tools 28.0.3
    • Java binary at: /opt/android-studio/jre/bin/java
    • Java version OpenJDK Runtime Environment (build 1.8.0_152-release-1248-b01)
    • All Android licenses accepted.

[!] Android Studio (version 3.3)
    • Android Studio at /opt/android-studio
    ✗ Flutter plugin not installed; this adds Flutter specific functionality.
    ✗ Dart plugin not installed; this adds Dart specific functionality.
    • Java version OpenJDK Runtime Environment (build 1.8.0_152-release-1248-b01)

[!] Android Studio
    • Android Studio at /home/chip/android-studio
    ✗ Flutter plugin not installed; this adds Flutter specific functionality.
    ✗ Dart plugin not installed; this adds Dart specific functionality.
    ✗ Unable to find bundled Java version.
    • Try updating or re-installing Android Studio.

[✓] Connected device (1 available)
    • SM G930F • ce081718cde4393e01 • android-arm64 • Android 8.0.0 (API 26)

! Doctor found issues in 2 categories.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions