Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

async -> sync #1006

Closed
wants to merge 1 commit into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 2 additions & 1 deletion TestsExample/App.js
Original file line number Diff line number Diff line change
Expand Up @@ -46,7 +46,8 @@ import Test865 from './src/Test865';
import Test881 from './src/Test881';
import Test898 from './src/Test898';
import Test913 from './src/Test913';
import SuperTest from './src/TestNestedNavigators';

export default function App() {
return <Test42 />;
return <Test648 />;
}
2 changes: 1 addition & 1 deletion TestsExample/src/Test263.js
Original file line number Diff line number Diff line change
Expand Up @@ -90,7 +90,7 @@ export default function ReactNativeScreensBugs() {
<NavigationContainer>
<NativeStack.Navigator
screenOptions={{
headerTranslucent: true,
headerTranslucent: false,
stackPresentation: 'modal',
}}>
<NativeStack.Screen
Expand Down
33 changes: 11 additions & 22 deletions TestsExample/src/Test42.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -2,32 +2,24 @@
import React from 'react';
import {NavigationContainer, ParamListBase} from '@react-navigation/native';
import {ScrollView, Button, Text} from 'react-native';
import {createNativeStackNavigator, NativeStackNavigationProp} from 'react-native-screens/native-stack';
//import {createNativeStackNavigator, NativeStackNavigationProp} from 'react-native-screens/native-stack';
import {createBottomTabNavigator} from '@react-navigation/bottom-tabs';
// import {createStackNavigator} from '@react-navigation/stack';
import {createStackNavigator} from '@react-navigation/stack';

const Stack = createNativeStackNavigator();
const Stack = createStackNavigator();

export default function NativeNavigation() {
return (
<NavigationContainer>
<Stack.Navigator
screenOptions={{
stackPresentation: 'modal',
}}>
<Stack.Screen
name="Home"
component={Home}
options={{
screenOrientation: 'portrait_up',
}}
/>
>
<Stack.Screen
name="NestedNavigator"
component={NestedNavigator}
options={{
screenOrientation: 'landscape_right',
}}
/>
<Stack.Screen
name="Home"
component={Home}
/>
</Stack.Navigator>
</NavigationContainer>
Expand All @@ -51,18 +43,15 @@ const NestedNavigator = () => (
</Tab.Navigator>
);

const InnerStack = createNativeStackNavigator();
const InnerStack = createStackNavigator();

const Inner = () => (
<InnerStack.Navigator
screenOptions={{
screenOrientation: 'portrait_down',
}}>
<InnerStack.Navigator>
<InnerStack.Screen name="DeeperHome" component={Home} />
</InnerStack.Navigator>
);

function Home({navigation}: {navigation: NativeStackNavigationProp<ParamListBase>}) {
function Home({navigation}: {navigation: any}) {
const [yes, setYes] = React.useState(true);
return (
<ScrollView
Expand Down
7 changes: 5 additions & 2 deletions TestsExample/src/Test556.js
Original file line number Diff line number Diff line change
Expand Up @@ -2,13 +2,16 @@ import * as React from 'react';
import {Button} from 'react-native';
import {NavigationContainer} from '@react-navigation/native';
import {createNativeStackNavigator} from 'react-native-screens/native-stack';
import {createStackNavigator} from '@react-navigation/stack';

const Stack = createNativeStackNavigator();
const Stack = createStackNavigator();

export default function App() {
return (
<NavigationContainer>
<Stack.Navigator>
<Stack.Navigator screenOptions={{
animationEnabled: false,
}}>
<Stack.Screen name="First" component={First} />
<Stack.Screen
name="Second"
Expand Down
2 changes: 1 addition & 1 deletion TestsExample/src/Test648.js
Original file line number Diff line number Diff line change
Expand Up @@ -39,7 +39,7 @@ function Second({navigation}) {
<ScrollView>
<Button
title="Tap me for first screen"
onPress={() => navigation.navigate('First')}
onPress={() => navigation.push('Second')}
/>
</ScrollView>
);
Expand Down
54 changes: 54 additions & 0 deletions TestsExample/src/TestNestedNavigators.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,54 @@
import React, { useEffect } from 'react';
import { View, Text } from 'react-native';
import { createStackNavigator } from '@react-navigation/stack';
import { NavigationContainer } from '@react-navigation/native';
const levels = 2;
const Stack = createStackNavigator();

function RandomStack(props: any) {
const {navigation, route, level} = props;

if (level === 0) {
console.log("level props", level, Object.keys(route));
return (
<View>
<Text> {"level route " + level + " " + route.name} </Text>
</View>
);
}
if (false && level != levels) {
const isFocused = navigation.isFocused();
useEffect(() => {
if (isFocused) {
const stay = Math.random() < 0.9;
const next = Math.round(Math.random() * 99) % 3;
const sib = stay ? route.name : next.toString();
navigation.navigate(
sib,
);
}
}, [isFocused]);
}

return (
<Stack.Navigator>
<Stack.Screen name="0" >
{ (props) => <RandomStack {...props} level={level-1}/> }
</Stack.Screen>
<Stack.Screen name="1" >
{ (props) => <RandomStack {...props} level={level-1}/> }
</Stack.Screen>
<Stack.Screen name="2" >
{ (props) => <RandomStack {...props} level={level-1}/> }
</Stack.Screen>
</Stack.Navigator>
);
}

export default function NestedStacksExample() {
return (
<NavigationContainer>
<RandomStack level={levels} />
</NavigationContainer>
);
}
65 changes: 12 additions & 53 deletions android/src/main/java/com/swmansion/rnscreens/ScreenContainer.java
Original file line number Diff line number Diff line change
Expand Up @@ -23,17 +23,7 @@ public class ScreenContainer<T extends ScreenFragment> extends ViewGroup {
protected final ArrayList<T> mScreenFragments = new ArrayList<>();

protected @Nullable FragmentManager mFragmentManager;
private @Nullable FragmentTransaction mCurrentTransaction;
private @Nullable FragmentTransaction mProcessingTransaction;
private boolean mNeedUpdate;
private boolean mIsAttached;
private final ChoreographerCompat.FrameCallback mFrameCallback =
new ChoreographerCompat.FrameCallback() {
@Override
public void doFrame(long frameTimeNanos) {
updateIfNeeded();
}
};
private boolean mLayoutEnqueued = false;
private final ChoreographerCompat.FrameCallback mLayoutCallback =
new ChoreographerCompat.FrameCallback() {
Expand All @@ -47,6 +37,7 @@ public void doFrame(long frameTimeNanos) {
}
};
private @Nullable ScreenFragment mParentScreenFragment = null;
private FragmentTransaction mCurrentTransaction = null;

public ScreenContainer(Context context) {
super(context);
Expand Down Expand Up @@ -100,14 +91,7 @@ public boolean isNested() {
}

protected void markUpdated() {
if (!mNeedUpdate) {
mNeedUpdate = true;
// enqueue callback of NATIVE_ANIMATED_MODULE type as all view operations are executed in
// DISPATCH_UI type and we want the callback to be called right after in the same frame.
ReactChoreographer.getInstance()
.postFrameCallback(
ReactChoreographer.CallbackType.NATIVE_ANIMATED_MODULE, mFrameCallback);
}
updateIfNeeded();
}

protected void notifyChildUpdate() {
Expand Down Expand Up @@ -201,47 +185,36 @@ private void setupFragmentManager() {
}

protected FragmentTransaction getOrCreateTransaction() {
if (mCurrentTransaction == null) {
mCurrentTransaction = mFragmentManager.beginTransaction();
mCurrentTransaction.setReorderingAllowed(true);
if (mCurrentTransaction != null) {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

this seems to no longer be necessary if we create new transaction and then commit it with each single operation. As a consequence we wouldn't need the mCurrentTransaction field nor need to call getOrCreaeTransaction nor tryCommitTransaction

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think it was left for usage with ScreenStack, where we have animations in Fragments, so we want to concatenate all the operations into one and run animations on them. Btw, I would change the name commitNowAllowingStateLoss to something like commitTransaction.

return mCurrentTransaction;
}
mCurrentTransaction = mFragmentManager.beginTransaction();
mCurrentTransaction.setReorderingAllowed(true);
return mCurrentTransaction;
}

protected void tryCommitTransaction() {
protected void commitNowAllowingStateLoss() {
if (mCurrentTransaction != null) {
final FragmentTransaction transaction = mCurrentTransaction;
mProcessingTransaction = transaction;
mProcessingTransaction.runOnCommit(
new Runnable() {
@Override
public void run() {
if (mProcessingTransaction == transaction) {
// we need to take into account that commit is initiated with some other transaction
// while the previous one is still processing. In this case mProcessingTransaction
// gets overwritten and we don't want to set it to null until the second transaction
// is finished.
mProcessingTransaction = null;
}
}
});
mCurrentTransaction.commitAllowingStateLoss();
mCurrentTransaction.commitNowAllowingStateLoss();
mCurrentTransaction = null;
}
}

private void attachScreen(ScreenFragment screenFragment) {
getOrCreateTransaction().add(getId(), screenFragment);
commitNowAllowingStateLoss();
}

private void moveToFront(ScreenFragment screenFragment) {
FragmentTransaction transaction = getOrCreateTransaction();
transaction.remove(screenFragment);
transaction.add(getId(), screenFragment);
commitNowAllowingStateLoss();
}

private void detachScreen(ScreenFragment screenFragment) {
getOrCreateTransaction().remove(screenFragment);
commitNowAllowingStateLoss();
}

protected Screen.ActivityState getActivityState(ScreenFragment screenFragment) {
Expand All @@ -256,7 +229,6 @@ protected boolean hasScreen(ScreenFragment screenFragment) {
protected void onAttachedToWindow() {
super.onAttachedToWindow();
mIsAttached = true;
mNeedUpdate = true;
setupFragmentManager();
}

Expand Down Expand Up @@ -323,24 +295,13 @@ protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
}

private void updateIfNeeded() {
if (!mNeedUpdate || !mIsAttached || mFragmentManager == null) {
if (!mIsAttached || mFragmentManager == null) {
return;
}
mNeedUpdate = false;
onUpdate();
}

private final void onUpdate() {
// We double check if fragment manager have any pending transactions to run.
// In performUpdate we often check whether some fragments are added to
// manager to avoid adding them for the second time (which result in crash).
// By design performUpdate should be called at most once per frame, so this
// should never happen, but in case there are some pending transaction we
// need to flush them here such that Fragment#isAdded checks reflect the
// reality and that we don't have enqueued fragment add commands that will
// execute shortly and cause "Fragment already added" crash.
mFragmentManager.executePendingTransactions();

performUpdate();
notifyContainerUpdate();
}
Expand Down Expand Up @@ -386,8 +347,6 @@ protected void performUpdate() {
}
screenFragment.getScreen().setTransitioning(transitioning);
}

tryCommitTransaction();
}

protected void notifyContainerUpdate() {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -307,7 +307,7 @@ public void run() {
mStack.clear();
mStack.addAll(mScreenFragments);

tryCommitTransaction();
commitNowAllowingStateLoss();

if (mTopScreen != null) {
setupBackHandlerIfNeeded(mTopScreen);
Expand Down Expand Up @@ -363,7 +363,7 @@ private void setupBackHandlerIfNeeded(ScreenStackFragment topScreen) {
.show(topScreen)
.addToBackStack(BACK_STACK_TAG)
.setPrimaryNavigationFragment(topScreen)
.commitAllowingStateLoss();
.commitNowAllowingStateLoss();
mFragmentManager.addOnBackStackChangedListener(mBackStackListener);
}
}
Expand Down