Skip to content

Conversation

WoLewicki
Copy link
Contributor

Summary:

This PR introduces kind of the same API that is available on iOS for subscribing to view mutations (see https://github.com/facebook/react-native/blob/67384cf5a07662b5030c20cf666b0f10b402bf23/packages/react-native/React/Fabric/Mounting/RCTMountingTransactionObserving.h) but for Android. The concept is needed there for e.g. for native-stack, with the same use case as on iOS, where we want to know that the views will be removed to start transition on them, and we need to know it before they are removed (and it is done in a bottom-up manner on new arch).

The current implementation uses UIManagerModule as the place where the listeners live, since it is possible to get to this module both from this code and from library's code. All the mutations are first added to an array, then the listeners are fired, and the changes are applied afterwards.

Changelog:

[ANDROID] [ADDED] - Listener for view mutations

Test Plan:

Run the RNTester app and see that all mutations are still mounted correctly. Add subscriber and see that you can check the mutations and act based on them in other components before they are mounted.

@facebook-github-bot facebook-github-bot added CLA Signed This label is managed by the Facebook bot. Authors need to sign the CLA before a PR can be reviewed. p: Software Mansion Partner: Software Mansion Partner labels Oct 9, 2023
@WoLewicki WoLewicki changed the title feat: make view recycling optional on iOS feat: add listener for mount operations on Android Oct 9, 2023
@WoLewicki
Copy link
Contributor Author

cc @cortinico if you could check the PR if the current direction is correct, or maybe cc someone that could help with merging it?

@facebook-github-bot facebook-github-bot added the Shared with Meta Applied via automation to indicate that an Issue or Pull Request has been shared with the team. label Oct 9, 2023
@arushikesarwani94
Copy link
Contributor

Could you address the Circle CI failures here before the merge ?

@analysis-bot
Copy link

analysis-bot commented Oct 17, 2023

Platform Engine Arch Size (bytes) Diff
android hermes arm64-v8a 17,163,267 +8
android hermes armeabi-v7a n/a --
android hermes x86 n/a --
android hermes x86_64 n/a --
android jsc arm64-v8a 20,542,635 +2
android jsc armeabi-v7a n/a --
android jsc x86 n/a --
android jsc x86_64 n/a --

Base commit: c5258b5
Branch: main

@WoLewicki
Copy link
Contributor Author

@arushikesarwani94 all the checks are passing now 🚀

@cipolleschi
Copy link
Contributor

cc. @cortinico @arushikesarwani94 could one of you lead the landing of this? 🙏

@cortinico
Copy link
Contributor

cc @mdvacca also

@WoLewicki
Copy link
Contributor Author

Did anyone have a chance to look at it? It would be perfect if it could land before 0.74 is cut.

@cipolleschi
Copy link
Contributor

I created an internal task in our backlog. We are starting a periodical review of those pending tasks on Monday afternoon and Wednesday afternoon, so expect some answer by Tuesday, probably.

I'm sorry that it is taking so long. :(

@cortinico
Copy link
Contributor

/rebase

@Obhenimen
Copy link

Please when will this PR be merged

@WoLewicki
Copy link
Contributor Author

@cortinico do you want me to rebase or does this comment does it automatically?

@cortinico
Copy link
Contributor

@cortinico do you want me to rebase or does this comment does it automatically?

@WoLewicki if you could rebase manually that would be really helpful.
We're discussing internally how to move forward with this change. We'll get back to you once we know what are the next steps (rebasing is needed anyway)

@WoLewicki
Copy link
Contributor Author

Ok I rebased, let me know if you have any info about it 🚀

@mdvacca
Copy link
Contributor

mdvacca commented Jan 31, 2024

Thanks for the work and for rebasing, I will take a look at it today or tomorrow.

Two things that stand up:

  • we shouldn't use UIManagerModule from fabric code
  • This change is in the critical path of React Native rendering, potentially affecting rendering perf during initial render of screens, @WoLewicki what's your opinion on perf implications of the PR?

@WoLewicki
Copy link
Contributor Author

we shouldn't use UIManagerModule from fabric code

Do you suggest some other approach? I'm not sure how could it be done differently.

This change is in the critical path of React Native rendering, potentially affecting rendering perf during initial render of screens, @WoLewicki what's your opinion on perf implications of the PR?

I am aware that it is critical and I haven't noticed any immediate performance drops. I'm making small, short lived objects that keep the information for listeners and then are used for dispatching the mutations. As long as it is not introducing performance decrease, it should be fine.

@mdvacca
Copy link
Contributor

mdvacca commented Feb 10, 2024

I am aware that it is critical and I haven't noticed any immediate performance drops. I'm making small, short lived objects that keep the information for listeners and then are used for dispatching the mutations. As long as it is not introducing performance decrease, it should be fine.

The initial implementation also relied on small short lived objects, but we've refactored the code this way because we found regressions on low end devices. I'm curious, how did you measure and confirmed there is no performance drop? We could try again, but we will need to refactor the code, add a feature flag and create an a/b testing to verify lack of performance regressions.

we shouldn't use UIManagerModule from fabric code
Do you suggest some other approach? I'm not sure how could it be done differently.

One approach is adding a method in UIManager and implement it inside FabricUIManager.
Although, I wonder if instead we should expose a new method inside UIManagerListener.java, and then call it from FabricUIManager.didMountItems, what do you think?

mIntBuffer[i++] == 1);
int reactTag = mIntBuffer[i++];
View view = null;
if (surfaceMountingManager.getViewExists(reactTag)) {
Copy link
Contributor

Choose a reason for hiding this comment

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

Other than creating objects we are increasing cost of this method my resolving Views earlier just to share with the listener, but we are not reusing these views on the call to surfaceMountingManager below, again this method is part of the critical path, and this will bring unnecessary regressions

@mdvacca
Copy link
Contributor

mdvacca commented Feb 15, 2024

Just to provide a quick update here.
We are discussing internally about adding or not this new API, if it is decided to proceed with this new API, then we will probably lead the development to move a bit faster and reduce back and forth in github reviews.

@WoLewicki it would be really helpful if you can provide concrete examples of usages of this API. for example current usages of RCTMountingTransactionObserving where you are making usage of the MountingTransaction objects. or how would you use MountingTransaction objects in Android

Thank you!

cc @cortinico

@WoLewicki
Copy link
Contributor Author

I'm curious, how did you measure and confirmed there is no performance drop?

Tbh, I did not test it extensively, just in the example app for react-native-screens. I wanted to rely on your testing to see if the performance is good enough still 😅

it would be really helpful if you can provide concrete examples of usages of this API. for example current usages of RCTMountingTransactionObserving where you are making usage of the MountingTransaction objects. or how would you use MountingTransaction objects in Android

As I mentioned in the description, it would be basically the same as on iOS in react-native-screens: https://github.com/software-mansion/react-native-screens/blob/58da3e2cb884fecd4d6ae9b51a45e9d596621fc6/ios/RNSScreenStack.mm#L1147 where we need to know if the screen from navigator will be destroyed in next transaction. Do you want me to find the exact code that would be used on Android with it?

@mdvacca
Copy link
Contributor

mdvacca commented Feb 20, 2024

Do you want me to find the exact code that would be used on Android with it?

We are mostly interested to understand what information you need from the mountingTranstacion/mountItem, just the type and component name as you do in iOS?

@WoLewicki
Copy link
Contributor Author

just the type and component name as you do in iOS?

Yes, exactly.

@WoLewicki
Copy link
Contributor Author

Not sure if some other libs would like to have more information, but for react-native-screens the same information as on iOS is enough now.

@mdvacca
Copy link
Contributor

mdvacca commented Mar 3, 2024

@WoLewicki thanks again for opening the discussion on exposing mount operations in Android and for implementing this PR

We've discussed internally about this PR and we have several concerns to move forward with it:

  • This API is exposing internal implementation details of the Renderer of React Native, adding this new API in Android might block us to extend or refactor React Native renderer in the future.
  • The PR is adding complexity on the execution of MountItems which can negatively affect performance on the critical path of React Native Renderer (which is already super perf sensitive in low end devices)
  • The proposed use cases can we achieved by using other APIs, for example if you want to know if a view is being destroyed/deleted for the "RNSScreenStack" ViewManager, you could override the removeViewAt / removeView methods in "RNSScreenStack" ViewManager instead e.g. see:
    public void removeViewAt(T parent, int index) {
    UiThreadUtil.assertOnUiThread();
    parent.removeViewAt(index);
    }
    public void removeView(T parent, View view) {
  • We've revisited mountingTransactionWillMount iOS API and we noticed that this API is overexposing MountingTransaction and we might revisit this in the near future. We have the goal of aligning APIs between Android and iOS, but in this case we might want to move away from exposing MountingTransaction in iOS instead of adding this API in Android.

I'm closing the PR because we decided that we won't add this API in React Native Android and we recommend overriding viewManager.removeViewAt() method instead.

CC @cortinico , @javache , @cipolleschi , @sammy-SC

@mdvacca mdvacca closed this Mar 3, 2024
@WoLewicki
Copy link
Contributor Author

The proposed use cases can we achieved by using other APIs, for example if you want to know if a view is being destroyed/deleted for the "RNSScreenStack" ViewManager, you could override the removeViewAt / removeView methods in "RNSScreenStack" ViewManager instead e.g. see:

yeah, we already use this mechanism on old arch: https://github.com/software-mansion/react-native-screens/blob/3b35894f1f83bc4c9daa518d68f3bcb0e832129a/android/src/main/java/com/swmansion/rnscreens/ScreenStackViewManager.kt#L33. The problem is the same as on iOS though. Because of the removals being dispatched bottom-up now, when we get to removeViewAt in the ScreenStack, all of the children are already unmounted and we can do nothing about it. Or am I missing something @mdvacca ?

@WoLewicki
Copy link
Contributor Author

Hey! I took another approach for getting the list of mutations that is unified between iOS and Android: software-mansion/react-native-screens#2134. It makes subscribing to RCTMountingTransactionObserving unnecessary, which seems like the way to go! We use the mechanism that was made for LayoutAnimations, namely setMountingOverrideDelegate.

Could you elaborate if it is a proper solution? The only problem with it for now is that there can be only one delegate right now and react-native-reanimated also wants to use it for its LayoutAnimations. Should I make a PR making it an array of delegates instead of a single one? cc @mdvacca @javache @cortinico @cipolleschi @sammy-SC. Sorry for pinging you all but I am not sure who is the owner of that code.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
CLA Signed This label is managed by the Facebook bot. Authors need to sign the CLA before a PR can be reviewed. p: Software Mansion Partner: Software Mansion Partner Shared with Meta Applied via automation to indicate that an Issue or Pull Request has been shared with the team.
Projects
None yet
Development

Successfully merging this pull request may close these issues.

8 participants