Repository navigation
FlutterFragment fails to render after being overlaid by a FlutterActivity #31264
Copy link
Copy link
Closed
Labels
platform-androidAndroid applications specificallyAndroid applications specifically
Description
When an AppCompatActivity contains a FlutterFragment, and an intent is fired to launch a FlutterActivity, when navigating back to the parent AppCompatActivity, the FlutterFragment is not rendered and is blank.
The Kotlin code for replicating this is:
// Copyright 2019 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
package io.flutter.addfluttertoandroid
import android.content.Context
import android.content.Intent
import android.os.Bundle
import android.support.annotation.NonNull
import android.support.design.widget.BottomNavigationView
import android.support.v4.app.Fragment
import android.support.v7.app.AppCompatActivity
import android.util.Log
import android.widget.TextView
import io.flutter.embedding.android.FlutterFragment
import io.flutter.embedding.engine.FlutterEngine
import kotlinx.android.synthetic.main.activity_main.*
import android.view.*
import io.flutter.embedding.android.FlutterActivity
import io.flutter.embedding.android.FlutterView
class MainActivity : AppCompatActivity() {
private val mOnNavigationItemSelectedListener = BottomNavigationView.OnNavigationItemSelectedListener { item ->
when (item.itemId) {
R.id.navigation_home -> {
addFragment("I am an Android Fragment!!!")
return@OnNavigationItemSelectedListener true
}
R.id.navigation_dashboard -> {
addFragment("I am a second Android Fragment!!!")
return@OnNavigationItemSelectedListener true
}
R.id.navigation_notifications -> {
addFlutterFragment()
return@OnNavigationItemSelectedListener true
}
}
false
}
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main_linear)
addFragment("I am an Android Fragment!!!")
navigation.setOnNavigationItemSelectedListener(mOnNavigationItemSelectedListener)
}
override fun onCreateOptionsMenu(menu: Menu): Boolean {
menuInflater.inflate(R.menu.action_menu, menu)
return true
}
override fun onOptionsItemSelected(item: MenuItem) = when (item.itemId) {
R.id.action_favorite -> {
Log.i("onCreate", "Menu item selected")
launchFlutterActivity()
true
}
else -> {
super.onOptionsItemSelected(item)
}
}
private fun addFragment(text: String) {
supportFragmentManager
.beginTransaction()
.replace(R.id.fragment_container,
AndroidFragment.newInstance(text))
.commit()
}
private fun addFlutterFragment() {
supportFragmentManager.beginTransaction()
.replace(R.id.fragment_container,
MyFlutterFragment.newInstance())
.commit()
}
private fun launchFlutterActivity() =
// startActivity(Intent(this, MyFlutterActivity::class.java))
startActivity(Intent(this, MyFlutterActivity::class.java))
}
class AndroidFragment : Fragment() {
companion object {
fun newInstance(text: String): AndroidFragment {
val fragment = AndroidFragment()
val args = Bundle()
args.putString("text", text)
fragment.arguments = args
return fragment
}
}
override fun onCreateView(
inflater: LayoutInflater, container: ViewGroup?,
savedInstanceState: Bundle?
): View? {
val view = inflater.inflate(R.layout.fragment_main, container, false)
arguments?.getString("text").let {
view.findViewById<TextView>(R.id.fragment_message).setText(it)
}
return view
}
}
class MyFlutterFragment : FlutterFragment() {
companion object {
@JvmStatic
fun newInstance() =
MyFlutterFragment().apply {
return FlutterFragment.Builder(MyFlutterFragment::class.java)
.renderMode(FlutterView.RenderMode.surface)
.transparencyMode(FlutterView.TransparencyMode.transparent)
.build<MyFlutterFragment>()
}
}
override fun createFlutterEngine(@NonNull context: Context): FlutterEngine =
(context.applicationContext as MyApplication).engine
override fun retainFlutterEngineAfterFragmentDestruction() = true
}
class MyFlutterActivity : FlutterActivity(), FlutterFragment.FlutterEngineProvider {
override fun getFlutterEngine(context: Context): FlutterEngine? =
(context.applicationContext as MyApplication).engine
}
If you navigate first to 'Notifications' in the bottom nav bar, and then tap on the action button in the app bar, then tap the back button to return to the first activity, the FlutterFragment will not render.
Reactions are currently unavailable
Metadata
Metadata
Assignees
Labels
platform-androidAndroid applications specificallyAndroid applications specifically
Activity
jason-simmons commentedon Apr 18, 2019
This app is trying to transfer a single
FlutterEngineinstance between FlutterViews in two different fragments. @matthew-carroll is that a supported scenario?The sequence is:
FlutterFragmentcontainingFlutterViewA.. The fragment'sonCreateViewcallsFlutterView.attachToFlutterEngineto bind theFlutterEngineto view A.FlutterFragmentcontainingFlutterViewB. B reuses the same engine instance and callsattachToFlutterEngineto bind the engine to B.FlutterFragmentis destroyed, anddetachFromFlutterEngineis called onFlutterViewB.onResumeis called on the firstFlutterFragment. But the firstFlutterFragmentdoes not reattach the shared engine instance toFlutterViewAmatthew-carroll commentedon Apr 20, 2019
@jason-simmons Yes, that scenario should be supported. I'll look into the attachment call as you mentioned and see if there is a more appropriate place for it to facilitate this use-case.
30639ee Allow FlutterEngine to be used on back-to-back screens (flutt…
30639ee Allow FlutterEngine to be used on back-to-back screens (flutt…
30639ee Allow FlutterEngine to be used on back-to-back screens (flutt…
Roll engine ef2bed6..39a950e (5 commits) (#32011)
github-actions commentedon Aug 30, 2021
This thread has been automatically locked since there has not been any recent activity after it was closed. If you are still experiencing a similar issue, please open a new bug, including the output of
flutter doctor -vand a minimal reproduction of the issue.