Skip to content

Commit bb14e87

Browse files
maciekstosiokkafar
authored andcommitted
fix(Android): crash API 25 when going back from screen with flat list (software-mansion#2964)
## Description Fixes software-mansion#2810 This PR should fix a crash when going back from the screen that has flat list. ## Changes There are two exceptions thrown: **First:** ``` Error: Exception in HostFunction: android.view.ViewRootImpl$CalledFromWrongThreadException: Only the original thread that created a view hierarchy can touch its views. ``` **Second:** ``` java.lang.IndexOutOfBoundsException: getChildDrawingOrder() returned invalid index 1 (child count is 1) ``` And it fails around this place in `Screen.kt`: ``` (...) if (parent is SwipeRefreshLayout && child is ImageView) { // SwipeRefreshLayout class which has CircleImageView as a child, // does not handle `startViewTransition` properly. // It has a custom `getChildDrawingOrder` method which returns // wrong index if we called `startViewTransition` on the views on new arch. // We add a simple View to bump the number of children to make it work. // TODO: find a better way to handle this scenario it.addView(View(context), i) } else { child?.let { view -> it.startViewTransition(view) } } (...) ``` Based on the comment, I assume `it.addView(View(context), i)` is to prevent the **second** crash. Because the **first** exception, we do not add "workaround" view, thus we run into **second**. We get the **first** exception, as the operation is performed from different thread, thus I ensure the adding view is performed from UIThread. ## Test code and steps to reproduce <details> <summary>Source code</summary> ``` import * as React from 'react'; import { View, Text, FlatList } from 'react-native'; import { NavigationContainer, useNavigation } from '@react-navigation/native'; import { createNativeStackNavigator, NativeStackScreenProps } from '@react-navigation/native-stack'; import { Button } from '@react-navigation/elements'; import { SafeAreaProvider } from 'react-native-safe-area-context'; type StackParamList = { Home: undefined; Details: undefined; }; function HomeScreen() { const navigation = useNavigation<NativeStackScreenProps<StackParamList, 'Home'>['navigation']>(); return ( <View style={{ flex: 1, alignItems: 'center', justifyContent: 'center' }}> <Text>Home Screen</Text> <Button onPress={() => navigation.navigate('Details')}> Go to Details </Button> </View> ); } function DetailsScreen() { const [isRefreshing, setIsRefreshing] = React.useState(false); return ( <View style={{ flex: 1, alignItems: 'center', justifyContent: 'center' }}> <FlatList data={[1, 2, 3, 4, 5]} renderItem={({ item }) => <Text>{item}</Text>} onRefresh={() => { return new Promise<void>((resolve) => { setIsRefreshing(true); setTimeout(() => { resolve(); }, 3000); }).then(() => { setIsRefreshing(false); }); }} refreshing={isRefreshing} /> </View> ); } const Stack = createNativeStackNavigator<StackParamList>(); function NestedStack() { return ( <Stack.Navigator> <Stack.Screen name="Home" component={HomeScreen} /> <Stack.Screen name="Details" component={DetailsScreen} /> </Stack.Navigator> ); } export default function App() { return ( <SafeAreaProvider> <NavigationContainer> <NestedStack /> </NavigationContainer> </SafeAreaProvider> ); }; ``` </details> ## Checklist - [x] Included code example that can be used to test this change - [ ] Ensured that CI passes --------- Co-authored-by: Kacper Kafara <[email protected]>
1 parent 188a305 commit bb14e87

File tree

1 file changed

+7
-1
lines changed

1 file changed

+7
-1
lines changed

android/src/fabric/java/com/swmansion/rnscreens/NativeProxy.kt

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -59,7 +59,13 @@ class NativeProxy {
5959

6060
val screen = weakScreeRef.get()
6161
if (screen is Screen) {
62-
screen.startRemovalTransition()
62+
val isScheduled =
63+
screen.post {
64+
screen.startRemovalTransition()
65+
}
66+
if (!isScheduled) {
67+
Log.w("[RNScreens]", "Failed to schedule removal transition start for screen with tag $screenTag")
68+
}
6369
} else {
6470
Log.w("[RNScreens]", "Reference stored in NativeProxy for tag $screenTag no longer points to valid object.")
6571
}

0 commit comments

Comments
 (0)