Skip to content

Commit fea5956

Browse files
authored
[Android] Remove early fragment removal logic. (#206)
1 parent 6155ffc commit fea5956

File tree

3 files changed

+14
-54
lines changed

3 files changed

+14
-54
lines changed

formula-android-tests/src/main/java/com/instacart/formula/test/TestFragmentActivity.kt

+8-2
Original file line numberDiff line numberDiff line change
@@ -26,7 +26,7 @@ class TestFragmentActivity : FormulaAppCompatActivity() {
2626
}
2727
}
2828

29-
fun navigateTo(key: FragmentKey) {
29+
fun navigateTo(key: FragmentKey, allowStateLoss: Boolean = false) {
3030
val entryIndex = supportFragmentManager.backStackEntryCount - 1
3131
val fragment = if (entryIndex >= 0) {
3232
val entry = supportFragmentManager.getBackStackEntryAt(entryIndex)
@@ -41,7 +41,13 @@ class TestFragmentActivity : FormulaAppCompatActivity() {
4141
}
4242
add(R.id.activity_content, FormulaFragment.newInstance(key), key.tag)
4343
addToBackStack(key.tag)
44-
}.commit()
44+
}.apply {
45+
if (allowStateLoss) {
46+
commitAllowingStateLoss()
47+
} else {
48+
commit()
49+
}
50+
}
4551
}
4652

4753
override fun onBackPressed() {

formula-android-tests/src/test/java/com/instacart/formula/FragmentFlowRenderViewTest.kt

+4-2
Original file line numberDiff line numberDiff line change
@@ -28,13 +28,15 @@ class FragmentFlowRenderViewTest {
2828

2929
private var lastState: FragmentFlowState? = null
3030
private val stateChangeRelay = PublishRelay.create<Pair<FragmentContract<*>, Any>>()
31+
private var onPreCreated: (TestFragmentActivity) -> Unit = {}
3132
private val formulaRule = TestFormulaRule(
3233
initFormula = { app ->
3334
FormulaAndroid.init(app) {
3435
activity<TestFragmentActivity> {
3536
store(
3637
configureActivity = {
3738
initialContract = TestContract()
39+
onPreCreated(this)
3840
},
3941
onRenderFragmentState = { a, state ->
4042
lastState = state
@@ -205,9 +207,9 @@ class FragmentFlowRenderViewTest {
205207
scenario.onActivity { it.onBackPressed() }
206208
}
207209

208-
private fun navigateToTaskDetail(id: Int = 1) {
210+
private fun navigateToTaskDetail(id: Int = 1, allowStateLoss: Boolean = false) {
209211
scenario.onActivity {
210-
it.navigateTo(TestContractWithId(id))
212+
it.navigateTo(TestContractWithId(id), allowStateLoss = allowStateLoss)
211213
}
212214
}
213215

formula-android/src/main/java/com/instacart/formula/android/internal/FragmentFlowRenderView.kt

+2-50
Original file line numberDiff line numberDiff line change
@@ -39,10 +39,6 @@ internal class FragmentFlowRenderView(
3939
private var fragmentState: FragmentFlowState? = null
4040
private val visibleFragments: LinkedList<Fragment> = LinkedList()
4141

42-
private var removedEarly = mutableListOf<FragmentId>()
43-
private var backStackEntries = mutableListOf<FragmentManager.BackStackEntry>()
44-
private var stateRestored: Boolean = false
45-
4642
private val featureProvider = object : FeatureProvider {
4743
override fun getFeature(id: FragmentId): FeatureEvent? {
4844
return fragmentState?.features?.get(id)
@@ -58,11 +54,6 @@ internal class FragmentFlowRenderView(
5854
) {
5955
super.onFragmentViewCreated(fm, f, v, savedInstanceState)
6056

61-
if (!stateRestored) {
62-
recordBackstackChange()
63-
stateRestored = true
64-
}
65-
6657
visibleFragments.add(f)
6758

6859
fragmentState?.let {
@@ -98,9 +89,7 @@ internal class FragmentFlowRenderView(
9889
visibleFragments.remove(f)
9990

10091
notifyLifecycleStateChanged(f, Lifecycle.State.DESTROYED)
101-
if (!removedEarly.contains(f.getFormulaFragmentId())) {
102-
onFragmentViewStateChanged(f.getFormulaFragmentId(), false)
103-
}
92+
onFragmentViewStateChanged(f.getFormulaFragmentId(), false)
10493
}
10594

10695
override fun onFragmentAttached(fm: FragmentManager, f: Fragment, context: Context) {
@@ -125,19 +114,12 @@ internal class FragmentFlowRenderView(
125114
// Only trigger detach, when fragment is actually being removed from the backstack
126115
if (FragmentLifecycle.shouldTrack(f) && !FragmentLifecycle.isKept(fm, f)) {
127116
val event = FragmentLifecycle.createRemovedEvent(f)
128-
val wasRemovedEarly = removedEarly.remove(f.getFormulaFragmentId())
129-
if (!wasRemovedEarly) {
130-
onLifecycleEvent(event)
131-
}
117+
onLifecycleEvent(event)
132118
}
133119
}
134120
}
135121

136122
init {
137-
activity.supportFragmentManager.addOnBackStackChangedListener {
138-
recordBackstackChange()
139-
}
140-
141123
activity.supportFragmentManager.registerFragmentLifecycleCallbacks(callback, false)
142124
}
143125

@@ -176,36 +158,6 @@ internal class FragmentFlowRenderView(
176158
}
177159
}
178160

179-
private fun recordBackstackChange() {
180-
val backStackEntryCount = backStackEntries.size
181-
val newBackStackEntryCount = activity.supportFragmentManager.backStackEntryCount
182-
if (backStackEntryCount > newBackStackEntryCount) {
183-
val removedEntries = backStackEntries.drop(newBackStackEntryCount)
184-
removedEntries.forEach { removed ->
185-
val poppedFragmentName = removed.name
186-
if (poppedFragmentName != null) {
187-
visibleFragments.find { it.tag == poppedFragmentName }?.let { poppedFragment ->
188-
// In case backstack gets repopulated before onDestroyView/onFragmentDetached gets called,
189-
// we internally clear it so it doesn't potentially interfere with a fragment that could have the same contract
190-
removeFragment(poppedFragment)
191-
}
192-
}
193-
backStackEntries.remove(removed)
194-
}
195-
} else if (backStackEntryCount < newBackStackEntryCount) {
196-
for (i in backStackEntryCount until newBackStackEntryCount) {
197-
backStackEntries.add(activity.supportFragmentManager.getBackStackEntryAt(i))
198-
}
199-
}
200-
}
201-
202-
private fun removeFragment(fragment: Fragment) {
203-
onFragmentViewStateChanged(fragment.getFormulaFragmentId(), false)
204-
val event = FragmentLifecycle.createRemovedEvent(fragment)
205-
onLifecycleEvent(event)
206-
removedEarly.add(fragment.getFormulaFragmentId())
207-
}
208-
209161
/**
210162
* Creates a unique identifier the first time fragment is attached that
211163
* is persisted across configuration changes.

0 commit comments

Comments
 (0)