/// <summary>
        /// Destroy the <see cref="ReactInstanceManager"/>.
        /// </summary>
        public async Task DisposeAsync()
        {
            DispatcherHelpers.AssertOnDispatcher();

            // TODO: memory pressure hooks
            if (_useDeveloperSupport)
            {
                _devSupportManager.IsEnabled = false;
            }

            _lifecycleStateMachine.OnDestroy();
            _lifecycleStateMachine.SetContext(null);

            var currentReactContext = _currentReactContext;

            if (currentReactContext != null)
            {
                await currentReactContext.DisposeAsync();

                _currentReactContext = null;
                _hasStartedCreatingInitialContext = false;
            }

            ReactChoreographer.Dispose();
        }
Ejemplo n.º 2
0
        /// <summary>
        /// Adds a root view to the hierarchy.
        /// </summary>
        /// <param name="tag">The root view tag.</param>
        /// <param name="rootView">The root view.</param>
        /// <param name="themedRootContext">The React context.</param>
        public void AddRootView(
            int tag,
            SizeMonitoringCanvas rootView,
            ThemedReactContext themedRootContext)
        {
            // This is called on layout manager thread

            // Extract dispatcher
            var rootViewDispatcher = rootView.Dispatcher;

            // _dispatcherToOperationQueueInfo contains a mapping of CoreDispatcher to <UIViewOperationQueueInstance, # of ReactRootView instances>.
            // Operation queue instances are created lazily whenever an "unknown" CoreDispatcher is detected. Each operation queue instance
            // works together with one dedicated NativeViewHierarchyManager and one ReactChoreographer.
            // One operation queue is the "main" one:
            // - is coupled with the CoreApplication.MainView dispatcher
            // - drives animations in ALL views
            QueueInstanceInfo queueInfo;

            if (!_dispatcherToOperationQueueInfo.TryGetValue(rootViewDispatcher, out queueInfo))
            {
                // Queue instance doesn't exist for this dispatcher, we need to create

                // Find the CoreApplicationView associated to the new CoreDispatcher
                CoreApplicationView foundView = CoreApplication.Views.First(v => v.Dispatcher == rootViewDispatcher);

                // Create new ReactChoreographer for this view/dispatcher. It will only be used for its DispatchUICallback services
                ReactChoreographer reactChoreographer = ReactChoreographer.CreateSecondaryInstance(foundView);

                queueInfo = new QueueInstanceInfo()
                {
                    queueInstance = new UIViewOperationQueueInstance(
                        _reactContext,
                        new NativeViewHierarchyManager(_viewManagerRegistry, rootViewDispatcher, OnViewsDropped),
                        reactChoreographer),
                    rootViewCount = 1
                };

                // Add new tuple to map
                _dispatcherToOperationQueueInfo.Add(rootViewDispatcher, queueInfo);

                if (_active)
                {
                    // Simulate an OnResume from the correct dispatcher thread
                    // (OnResume/OnSuspend/OnDestroy have this thread affinity, all other methods do enqueuings in a thread safe manner)
                    DispatcherHelpers.RunOnDispatcher(rootViewDispatcher, queueInfo.queueInstance.OnResume, true); // inlining allowed
                }
            }
            else
            {
                // Queue instance does exist.
                // Increment the count of root views. This is helpful for the case the count reaches 0 so we can cleanup the queue.
                queueInfo.rootViewCount++;
            }

            // Add tag
            _reactTagToOperationQueue.Add(tag, queueInfo.queueInstance);

            // Send forward
            queueInfo.queueInstance.AddRootView(tag, rootView, themedRootContext);
        }
        /// <summary>
        /// Destroy the <see cref="ReactInstanceManager"/>.
        /// </summary>
        public async Task DisposeAsync()
        {
            DispatcherHelpers.AssertOnDispatcher();
            using (await _lock.LockAsync())
            {
                // TODO: memory pressure hooks
                if (_useDeveloperSupport)
                {
                    _devSupportManager.IsEnabled = false;
                }

                _lifecycleStateMachine.OnDestroy();
                _lifecycleStateMachine.SetContext(null);

                var currentReactContext = _currentReactContext;
                if (currentReactContext != null)
                {
                    await currentReactContext.DisposeAsync();

                    _currentReactContext = null;
                }

                ReactChoreographer.Dispose();
                DispatcherHelpers.Reset();
            }
        }
Ejemplo n.º 4
0
        private static ReactInstanceManager CreateReactInstanceManager(string jsBundleFile, LifecycleState initialLifecycleState = LifecycleState.Foreground)
        {
            ReactNative.Bridge.DispatcherHelpers.Initialize();
            ReactChoreographer.Initialize();

            return(new ReactInstanceManagerBuilder
            {
                InitialLifecycleState = initialLifecycleState,
                JavaScriptBundleFile = jsBundleFile,
            }.Build());
        }
        /// <summary>
        /// Trigger the React context initialization asynchronously in a
        /// background task. This enables applications to pre-load the
        /// application JavaScript, and execute global core code before the
        /// <see cref="ReactRootView"/> is available and measure. This should
        /// only be called the first time the application is set up, which is
        /// enforced to keep developers from accidentally creating their
        /// applications multiple times.
        /// </summary>
        /// <param name="token">A token to cancel the request.</param>
        /// <returns>A task to await the result.</returns>
        public Task <ReactContext> CreateReactContextAsync(CancellationToken token)
        {
            if (_hasStartedCreatingInitialContext)
            {
                throw new InvalidOperationException(
                          "React context creation should only be called when creating the React " +
                          "application for the first time. When reloading JavaScript, e.g., from " +
                          "a new file, explicitly, use the re-create method.");
            }

            ReactChoreographer.Initialize();
            _hasStartedCreatingInitialContext = true;
            return(CreateReactContextCoreAsync(token));
        }
        /// <summary>
        /// Trigger the React context initialization asynchronously in a
        /// background task. This enables applications to pre-load the
        /// application JavaScript, and execute global core code before the
        /// <see cref="ReactRootView"/> is available and measure. This should
        /// only be called the first time the application is set up, which is
        /// enforced to keep developers from accidentally creating their
        /// applications multiple times.
        /// </summary>
        /// <returns>A task to await the result.</returns>
        internal async Task CreateReactContextInBackgroundAsync()
        {
            if (_hasStartedCreatingInitialContext)
            {
                throw new InvalidOperationException(
                          "React context creation should only be called when creating the React " +
                          "application for the first time. When reloading JavaScript, e.g., from " +
                          "a new file, explicitly, use the re-create method.");
            }

            ReactChoreographer.Initialize();
            _hasStartedCreatingInitialContext = true;
            await RecreateReactContextInBackgroundInnerAsync().ConfigureAwait(false);
        }
        /// <summary>
        /// Used when the application resumes to reset the back button handling
        /// in JavaScript.
        /// </summary>
        /// <param name="onBackPressed">
        /// The action to take when back is pressed.
        /// </param>
        public void OnResume(Action onBackPressed)
        {
            DispatcherHelpers.Initialize();
            DispatcherHelpers.AssertOnDispatcher();
            ReactChoreographer.Initialize();

            _defaultBackButtonHandler = onBackPressed;
            _suspendCancellation      = new CancellationDisposable();

            if (_useDeveloperSupport)
            {
                _devSupportManager.IsEnabled = true;
            }

            _lifecycleStateMachine.OnResume();
        }
        /// <summary>
        /// Called when the application is suspended.
        /// </summary>
        public void OnSuspend()
        {
            DispatcherHelpers.AssertOnDispatcher();

            _defaultBackButtonHandler = null;
            _suspendCancellation?.Dispose();

            if (_useDeveloperSupport)
            {
                _devSupportManager.IsEnabled = false;
            }

            _lifecycleStateMachine.OnSuspend();

            ReactChoreographer.Dispose();
            DispatcherHelpers.Reset();
        }
Ejemplo n.º 9
0
        /// <summary>
        /// Awaits the currently initializing React context, or creates a new one.
        /// </summary>
        /// <param name="token">A token to cancel the request.</param>
        /// <returns>
        /// A task to await the React context.
        /// </returns>
        public async Task <ReactContext> GetOrCreateReactContextAsync(CancellationToken token)
        {
            DispatcherHelpers.AssertOnDispatcher();
            using (await _lock.LockAsync())
            {
                if (_hasStartedCreatingInitialContext)
                {
                    // By this point context has already been created due to the serialized aspect of context initialization.
                    return(_currentReactContext);
                }
                else
                {
                    _hasStartedCreatingInitialContext = true;

                    ReactChoreographer.Initialize();
                    return(await CreateReactContextCoreAsync(token));
                }
            }
        }
        /// <summary>
        /// Destroy the <see cref="ReactInstanceManager"/>.
        /// </summary>
        public async Task DisposeAsync()
        {
            DispatcherHelpers.AssertOnDispatcher();

            // TODO: memory pressure hooks
            if (_useDeveloperSupport)
            {
                _devSupportManager.IsEnabled = false;
            }

            MoveToBeforeCreateLifecycleState();

            var currentReactContext = _currentReactContext;

            if (currentReactContext != null)
            {
                await currentReactContext.DisposeAsync().ConfigureAwait(false);

                _currentReactContext = null;
                _hasStartedCreatingInitialContext = false;
            }

            ReactChoreographer.Dispose();
        }
 /// <summary>
 /// Instantiates the <see cref="UIViewOperationQueueInstance"/>.
 /// </summary>
 /// <param name="reactContext">The React context.</param>
 /// <param name="nativeViewHierarchyManager">
 /// The native view hierarchy manager associated with this instance.
 /// </param>
 /// <param name="reactChoreographer">
 /// The choreographer associated with this instance.
 /// </param>
 public UIViewOperationQueueInstance(ReactContext reactContext, NativeViewHierarchyManager nativeViewHierarchyManager, ReactChoreographer reactChoreographer)
 {
     _nativeViewHierarchyManager = nativeViewHierarchyManager;
     _reactContext       = reactContext;
     _reactChoreographer = reactChoreographer;
 }
 /// <summary>
 /// Trigger the React context initialization asynchronously in a
 /// background task. This enables applications to pre-load the
 /// application JavaScript, and execute global core code before the
 /// <see cref="ReactRootView"/> is available and measure. This should
 /// only be called the first time the application is set up, which is
 /// enforced to keep developers from accidentally creating their
 /// applications multiple times.
 /// </summary>
 public async void CreateReactContextInBackground()
 {
     ReactChoreographer.Initialize();
     await CreateReactContextInBackgroundAsync().ConfigureAwait(false);
 }