Skip to content

PlatformView.onFlutterViewAttached() called multiple times for single instance on Android #178136

@evil159

Description

@evil159

Steps to reproduce

  1. Run the app with flutter run on Android
  2. Tap "Show Native View" button
  3. Check logcat for "DummyNativeView" logs

sample_project.zip

Expected results

onFlutterViewAttached() should be called once per PlatformView instance.

Actual results

onFlutterViewAttached() is called multiple times for the same PlatformView instance:

Code sample

Code sample

lib/main.dart:

import 'package:flutter/material.dart';
import 'package:flutter/services.dart';

void main() {
  runApp(const MyApp());
}

class MyApp extends StatelessWidget {
  const MyApp({super.key});

  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      title: 'Platform View Test',
      home: const MyHomePage(),
    );
  }
}

class MyHomePage extends StatefulWidget {
  const MyHomePage({super.key});

  @override
  State<MyHomePage> createState() => _MyHomePageState();
}

class _MyHomePageState extends State<MyHomePage> {
  bool _showNativeView = false;

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: const Text('Platform View Test'),
      ),
      body: Column(
        children: [
          ElevatedButton(
            onPressed: () {
              setState(() {
                _showNativeView = !_showNativeView;
              });
            },
            child: Text(_showNativeView ? 'Hide Native View' : 'Show Native View'),
          ),
          Expanded(
            child: _showNativeView
                ? const AndroidView(
                    viewType: 'dummy_native_view',
                    layoutDirection: TextDirection.ltr,
                  )
                : const Center(
                    child: Text('Native view hidden'),
                  ),
          ),
        ],
      ),
    );
  }
}

android/app/src/main/kotlin/com/example/platform_view_test/MainActivity.kt:

package com.example.platform_view_test

import io.flutter.embedding.android.FlutterActivity
import io.flutter.embedding.engine.FlutterEngine

class MainActivity : FlutterActivity() {
    override fun configureFlutterEngine(flutterEngine: FlutterEngine) {
        super.configureFlutterEngine(flutterEngine)
        flutterEngine
            .platformViewsController
            .registry
            .registerViewFactory("dummy_native_view", DummyNativeViewFactory())
    }
}

android/app/src/main/kotlin/com/example/platform_view_test/DummyNativeViewFactory.kt:

package com.example.platform_view_test

import android.content.Context
import android.util.Log
import io.flutter.plugin.common.StandardMessageCodec
import io.flutter.plugin.platform.PlatformView
import io.flutter.plugin.platform.PlatformViewFactory

class DummyNativeViewFactory : PlatformViewFactory(StandardMessageCodec.INSTANCE) {
    override fun create(context: Context, viewId: Int, args: Any?): PlatformView {
        Log.i("DummyNativeView", "Factory.create() called - viewId: $viewId")
        return DummyNativeView(context, viewId)
    }
}

android/app/src/main/kotlin/com/example/platform_view_test/DummyNativeView.kt:

package com.example.platform_view_test

import android.content.Context
import android.graphics.Color
import android.util.Log
import android.view.View
import android.widget.TextView
import io.flutter.plugin.platform.PlatformView

class DummyNativeView(context: Context, private val viewId: Int) : PlatformView {
    private val textView: TextView = TextView(context)

    init {
        Log.i("DummyNativeView", "[$viewId] Constructor called")
        textView.apply {
            text = "Native Android View #$viewId"
            textSize = 20f
            setTextColor(Color.WHITE)
            setBackgroundColor(Color.BLUE)
            setPadding(40, 40, 40, 40)
        }
    }

    override fun getView(): View {
        Log.i("DummyNativeView", "[$viewId] getView() called")
        return textView
    }

    override fun dispose() {
        Log.i("DummyNativeView", "[$viewId] dispose() called")
    }

    override fun onFlutterViewAttached(flutterView: View) {
        Log.i("DummyNativeView", "[$viewId] onFlutterViewAttached() called")
    }

    override fun onFlutterViewDetached() {
        Log.i("DummyNativeView", "[$viewId] onFlutterViewDetached() called")
    }
}

Screenshots or Video

Screenshots / Video demonstration

[Upload media here]

Logs

Logs
DummyNativeView: Factory.create() called - viewId: 0
DummyNativeView: [0] Constructor called
DummyNativeView: [0] getView() called
DummyNativeView: [0] onFlutterViewAttached() called
DummyNativeView: [0] onFlutterViewAttached() called  <-- DUPLICATE CALL

Flutter Doctor output

Doctor output
[✓] Flutter (Channel stable, 3.35.7, on macOS 26.0.1 25A362 darwin-arm64, locale en-US) [571ms]
    • Flutter version 3.35.7 on channel stable at /Users/romanlaitarenko/Developer/flutter
    • Upstream repository https://github.com/flutter/flutter.git
    • Framework revision adc9010625 (2 weeks ago), 2025-10-21 14:16:03 -0400
    • Engine revision 035316565a
    • Dart version 3.9.2
    • DevTools version 2.48.0
    • Feature flags: enable-web, enable-linux-desktop, enable-macos-desktop, enable-windows-desktop, enable-android, enable-ios, cli-animations, enable-swift-package-manager,
      enable-lldb-debugging

[!] Android toolchain - develop for Android devices (Android SDK version 36.0.0) [1,378ms]
    • Android SDK at /Users/romanlaitarenko/Library/Android/sdk
    • Emulator version 35.5.10.0 (build_id 13402964) (CL:N/A)
    • Platform android-36, build-tools 36.0.0
    • ANDROID_HOME = /Users/romanlaitarenko/Library/Android/sdk
    • Java binary at: /Library/Java/JavaVirtualMachines/temurin-17.jdk/Contents/Home/bin/java
      This JDK is specified in your Flutter configuration.
      To change the current JDK, run: `flutter config --jdk-dir="path/to/jdk"`.
    • Java version OpenJDK Runtime Environment Temurin-17.0.16+8 (build 17.0.16+8)
    ! Some Android licenses not accepted. To resolve this, run: flutter doctor --android-licenses

[✓] Xcode - develop for iOS and macOS (Xcode 26.1) [992ms]
    • Xcode at /Applications/Xcode.app/Contents/Developer
    • Build 17B55
    • CocoaPods version 1.16.2

[✗] Chrome - develop for the web (Cannot find Chrome executable at /Applications/Google Chrome.app/Contents/MacOS/Google Chrome) [7ms]
    ! Cannot find Chrome. Try setting CHROME_EXECUTABLE to a Chrome executable.

[✓] Android Studio (version 2024.3) [7ms]
    • 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 21.0.6+-13368085-b895.109)

[✓] Connected device (3 available) [6.3s]
    • sdk gphone16k arm64 (mobile) • emulator-5554                        • android-arm64 • Android 15 (API 35) (emulator)
    • iPhone 17 Pro (mobile)       • 2701564F-9AAF-40CA-8418-AB8BD4C02655 • ios           • com.apple.CoreSimulator.SimRuntime.iOS-26-1 (simulator)
    • macOS (desktop)              • macos                                • darwin-arm64  • macOS 26.0.1 25A362 darwin-arm64
    ! Error: Browsing on the local area network for Roman’s iPhone (2). Ensure the device is unlocked and attached with a cable or associated with the same local area network as this
      Mac.
      The device must be opted into Developer Mode to connect wirelessly. (code -27)

[✓] Network resources [269ms]
    • All expected network resources are available.

! Doctor found issues in 2 categories.

Metadata

Metadata

Assignees

Labels

Bot is counting down the days until it unassigns the issueP1High-priority issues at the top of the work lista: platform-viewsEmbedding Android/iOS views in Flutter appsengineflutter/engine related. See also e: labels.found in release: 3.35Found to occur in 3.35found in release: 3.38Found to occur in 3.38has reproducible stepsThe issue has been confirmed reproducible and is ready to work onplatform-androidAndroid applications specificallyteam-androidOwned by Android platform team

Type

No type

Projects

No projects

Milestone

No milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions