From 56e99c84cbdacc6f06684fd15f6adfc49e93f36c Mon Sep 17 00:00:00 2001 From: Kevin Petit Date: Fri, 28 Jun 2019 12:53:49 +0200 Subject: [PATCH] [Android] Fix various issues in object dispose methods. (#6467) * Android - Fix various issues in object dispose methods. * Tear down old element before disposing the ItemViewAdapter. * More fixes. * NavigationPageRenderer - Reorder ResetToolbar and remove view before dispose ShellSectionRenderer - Call base.Destroy last + Remove and destroy _scrollview * Remove obsolete code. * Fix build. --- .../AppCompat/CarouselPageRenderer.cs | 39 ++++++---- .../AppCompat/FormsAppCompatActivity.cs | 16 ++-- .../AppCompat/ImageButtonRenderer.cs | 14 +++- .../AppCompat/MasterDetailPageRenderer.cs | 29 ++++---- .../AppCompat/NavigationPageRenderer.cs | 86 +++++++++++++--------- .../AppCompat/Platform.cs | 70 ++++++++++-------- .../AppCompat/ShellFragmentContainer.cs | 6 +- .../AppCompat/TabbedPageRenderer.cs | 30 +++++--- .../CollectionView/ItemsViewRenderer.cs | 3 - .../FastRenderers/AutomationPropertiesProvider.cs | 5 ++ .../FastRenderers/ButtonRenderer.cs | 8 +- .../FastRenderers/FrameRenderer.cs | 16 ++-- .../FastRenderers/ImageRenderer.cs | 9 ++- .../FastRenderers/LabelRenderer.cs | 10 ++- .../FastRenderers/VisualElementRenderer.cs | 9 ++- .../Renderers/ShellSectionRenderer.cs | 25 ++++--- .../VisualElementPackager.cs | 24 +++--- .../VisualElementRenderer.cs | 37 +++++----- 18 files changed, 254 insertions(+), 182 deletions(-) diff --git a/Xamarin.Forms.Platform.Android/AppCompat/CarouselPageRenderer.cs b/Xamarin.Forms.Platform.Android/AppCompat/CarouselPageRenderer.cs index 374febe..29b312b 100644 --- a/Xamarin.Forms.Platform.Android/AppCompat/CarouselPageRenderer.cs +++ b/Xamarin.Forms.Platform.Android/AppCompat/CarouselPageRenderer.cs @@ -1,4 +1,4 @@ -using System; +using System; using System.Collections.Specialized; using System.ComponentModel; using Android.Content; @@ -51,29 +51,38 @@ namespace Xamarin.Forms.Platform.Android.AppCompat if (disposing && !_disposed) { _disposed = true; - RemoveAllViews(); - foreach (ContentPage pageToRemove in Element.Children) - { - IVisualElementRenderer pageRenderer = Android.Platform.GetRenderer(pageToRemove); - if (pageRenderer != null) - { - pageRenderer.View.RemoveFromParent(); - pageRenderer.Dispose(); - } - pageToRemove.ClearValue(Android.Platform.RendererProperty); - } + + if (Element != null) + PageController.InternalChildren.CollectionChanged -= OnChildrenCollectionChanged; if (_viewPager != null) { + RemoveView(_viewPager); + + _viewPager.ClearOnPageChangeListeners(); _viewPager.Adapter.Dispose(); _viewPager.Dispose(); _viewPager = null; } - _previousPage = null; + RemoveAllViews(); - if (Element != null) - PageController.InternalChildren.CollectionChanged -= OnChildrenCollectionChanged; + _previousPage = null; + + if (Element?.Children != null) + { + foreach (ContentPage pageToRemove in Element.Children) + { + IVisualElementRenderer pageRenderer = Android.Platform.GetRenderer(pageToRemove); + if (pageRenderer != null) + { + pageRenderer.View.RemoveFromParent(); + pageRenderer.Dispose(); + } + + pageToRemove.ClearValue(Android.Platform.RendererProperty); + } + } } base.Dispose(disposing); diff --git a/Xamarin.Forms.Platform.Android/AppCompat/FormsAppCompatActivity.cs b/Xamarin.Forms.Platform.Android/AppCompat/FormsAppCompatActivity.cs index b3546f0..eb20ae6 100644 --- a/Xamarin.Forms.Platform.Android/AppCompat/FormsAppCompatActivity.cs +++ b/Xamarin.Forms.Platform.Android/AppCompat/FormsAppCompatActivity.cs @@ -211,6 +211,8 @@ namespace Xamarin.Forms.Platform.Android PopupManager.Unsubscribe(this); + _layout.RemoveView(Platform); + Platform?.Dispose(); // call at the end to avoid race conditions with Platform dispose @@ -227,6 +229,12 @@ namespace Xamarin.Forms.Platform.Android { _layout.HideKeyboard(true); + if (Forms.IsLollipopOrNewer) + { + // Don't listen for power save mode changes while we're paused + UnregisterReceiver(_powerSaveModeBroadcastReceiver); + } + // Stop animations or other ongoing actions that could consume CPU // Commit unsaved changes, build only if users expect such changes to be permanently saved when thy leave such as a draft email // Release system resources, such as broadcast receivers, handles to sensors (like GPS), or any resources that may affect battery life when your activity is paused. @@ -236,12 +244,6 @@ namespace Xamarin.Forms.Platform.Android _previousState = _currentState; _currentState = AndroidApplicationLifecycleState.OnPause; - if (Forms.IsLollipopOrNewer) - { - // Don't listen for power save mode changes while we're paused - UnregisterReceiver(_powerSaveModeBroadcastReceiver); - } - OnStateChanged(); } @@ -318,7 +320,7 @@ namespace Xamarin.Forms.Platform.Android } if (args.PropertyName == nameof(_application.MainPage)) - InternalSetPage(_application.MainPage); + SetMainPage(); if (args.PropertyName == PlatformConfiguration.AndroidSpecific.Application.WindowSoftInputModeAdjustProperty.PropertyName) SetSoftInputMode(); } diff --git a/Xamarin.Forms.Platform.Android/AppCompat/ImageButtonRenderer.cs b/Xamarin.Forms.Platform.Android/AppCompat/ImageButtonRenderer.cs index 2308e19..5a2ff05 100644 --- a/Xamarin.Forms.Platform.Android/AppCompat/ImageButtonRenderer.cs +++ b/Xamarin.Forms.Platform.Android/AppCompat/ImageButtonRenderer.cs @@ -83,6 +83,14 @@ namespace Xamarin.Forms.Platform.Android if (disposing) { + if (Element != null) + { + Element.PropertyChanged -= OnElementPropertyChanged; + } + + SetOnClickListener(null); + SetOnTouchListener(null); + OnFocusChangeListener = null; ImageElementManager.Dispose(this); @@ -94,11 +102,9 @@ namespace Xamarin.Forms.Platform.Android if (Element != null) { - Element.PropertyChanged -= OnElementPropertyChanged; - - if (Android.Platform.GetRenderer(Element) == this) + if (Platform.GetRenderer(Element) == this) { - Element.ClearValue(Android.Platform.RendererProperty); + Element.ClearValue(Platform.RendererProperty); } Element = null; diff --git a/Xamarin.Forms.Platform.Android/AppCompat/MasterDetailPageRenderer.cs b/Xamarin.Forms.Platform.Android/AppCompat/MasterDetailPageRenderer.cs index 96ab46a..4431abb 100644 --- a/Xamarin.Forms.Platform.Android/AppCompat/MasterDetailPageRenderer.cs +++ b/Xamarin.Forms.Platform.Android/AppCompat/MasterDetailPageRenderer.cs @@ -214,6 +214,22 @@ namespace Xamarin.Forms.Platform.Android.AppCompat if (disposing) { + Device.Info.PropertyChanged -= DeviceInfoPropertyChanged; + + if (Element != null) + { + MasterDetailPageController.BackButtonPressed -= OnBackButtonPressed; + Element.PropertyChanged -= HandlePropertyChanged; + Element.Appearing -= MasterDetailPageAppearing; + Element.Disappearing -= MasterDetailPageDisappearing; + } + + if (_masterLayout?.ChildView != null) + _masterLayout.ChildView.PropertyChanged -= HandleMasterPropertyChanged; + + if (!this.IsDisposed()) + RemoveDrawerListener(this); + if (_tracker != null) { _tracker.Dispose(); @@ -229,26 +245,13 @@ namespace Xamarin.Forms.Platform.Android.AppCompat if (_masterLayout != null) { - if (_masterLayout.ChildView != null) - _masterLayout.ChildView.PropertyChanged -= HandleMasterPropertyChanged; - RemoveView(_masterLayout); _masterLayout.Dispose(); _masterLayout = null; } - Device.Info.PropertyChanged -= DeviceInfoPropertyChanged; - - if (!this.IsDisposed()) - RemoveDrawerListener(this); - if (Element != null) { - MasterDetailPageController.BackButtonPressed -= OnBackButtonPressed; - Element.PropertyChanged -= HandlePropertyChanged; - Element.Appearing -= MasterDetailPageAppearing; - Element.Disappearing -= MasterDetailPageDisappearing; - Element.ClearValue(Android.Platform.RendererProperty); Element = null; } diff --git a/Xamarin.Forms.Platform.Android/AppCompat/NavigationPageRenderer.cs b/Xamarin.Forms.Platform.Android/AppCompat/NavigationPageRenderer.cs index c978e3b..5af5536 100644 --- a/Xamarin.Forms.Platform.Android/AppCompat/NavigationPageRenderer.cs +++ b/Xamarin.Forms.Platform.Android/AppCompat/NavigationPageRenderer.cs @@ -170,17 +170,46 @@ namespace Xamarin.Forms.Platform.Android.AppCompat if (disposing) { - if (_titleViewRenderer != null) + Device.Info.PropertyChanged -= DeviceInfoPropertyChanged; + + if (NavigationPageController != null) { - Android.Platform.ClearRenderer(_titleViewRenderer.View); - _titleViewRenderer.Dispose(); - _titleViewRenderer = null; + var navController = NavigationPageController; + + navController.PushRequested -= OnPushed; + navController.PopRequested -= OnPopped; + navController.PopToRootRequested -= OnPoppedToRoot; + navController.InsertPageBeforeRequested -= OnInsertPageBeforeRequested; + navController.RemovePageRequested -= OnRemovePageRequested; + } + + if (Current != null) + { + Current.PropertyChanged -= CurrentOnPropertyChanged; } + FragmentManager fm = FragmentManager; + + if (!fm.IsDestroyed) + { + FragmentTransaction trans = fm.BeginTransactionEx(); + foreach (Fragment fragment in _fragmentStack) + trans.RemoveEx(fragment); + trans.CommitAllowingStateLossEx(); + fm.ExecutePendingTransactionsEx(); + } + _toolbar.RemoveView(_titleView); _titleView?.Dispose(); _titleView = null; + if (_titleViewRenderer != null) + { + Android.Platform.ClearRenderer(_titleViewRenderer.View); + _titleViewRenderer.Dispose(); + _titleViewRenderer = null; + } + _toolbar.RemoveView(_titleIconView); _titleIconView?.Dispose(); _titleIconView = null; @@ -190,6 +219,10 @@ namespace Xamarin.Forms.Platform.Android.AppCompat if (_toolbarTracker != null) { _toolbarTracker.CollectionChanged -= ToolbarTrackerOnCollectionChanged; + + foreach (ToolbarItem item in _toolbarTracker.ToolbarItems) + item.PropertyChanged -= OnToolbarItemPropertyChanged; + _toolbarTracker.Target = null; _toolbarTracker = null; } @@ -197,6 +230,10 @@ namespace Xamarin.Forms.Platform.Android.AppCompat if (_toolbar != null) { _toolbar.SetNavigationOnClickListener(null); + _toolbar.Menu.Clear(); + + RemoveView(_toolbar); + _toolbar.Dispose(); _toolbar = null; } @@ -204,6 +241,8 @@ namespace Xamarin.Forms.Platform.Android.AppCompat if (_drawerLayout.IsAlive() && _drawerListener.IsAlive()) { _drawerLayout.RemoveDrawerListener(_drawerListener); + + RemoveView(_drawerLayout); } if (_drawerListener != null) @@ -239,31 +278,6 @@ namespace Xamarin.Forms.Platform.Android.AppCompat IVisualElementRenderer renderer = Android.Platform.GetRenderer(child); renderer?.Dispose(); } - - var navController = NavigationPageController; - - navController.PushRequested -= OnPushed; - navController.PopRequested -= OnPopped; - navController.PopToRootRequested -= OnPoppedToRoot; - navController.InsertPageBeforeRequested -= OnInsertPageBeforeRequested; - navController.RemovePageRequested -= OnRemovePageRequested; - } - - Device.Info.PropertyChanged -= DeviceInfoPropertyChanged; - - // API only exists on newer android YAY - if ((int)Build.VERSION.SdkInt >= 17) - { - FragmentManager fm = FragmentManager; - - if (!fm.IsDestroyed) - { - FragmentTransaction trans = fm.BeginTransactionEx(); - foreach (Fragment fragment in _fragmentStack) - trans.RemoveEx(fragment); - trans.CommitAllowingStateLossEx(); - fm.ExecutePendingTransactionsEx(); - } } } @@ -313,8 +327,6 @@ namespace Xamarin.Forms.Platform.Android.AppCompat oldNavController.RemovePageRequested -= OnRemovePageRequested; RemoveAllViews(); - if (_toolbar != null) - AddView(_toolbar); } if (e.NewElement != null) @@ -714,22 +726,24 @@ namespace Xamarin.Forms.Platform.Android.AppCompat { AToolbar oldToolbar = _toolbar; + _toolbar.SetNavigationOnClickListener(null); + _toolbar.RemoveFromParent(); + + _toolbar.RemoveView(_titleView); + _titleView = null; + if (_titleViewRenderer != null) { Android.Platform.ClearRenderer(_titleViewRenderer.View); + _titleViewRenderer.Dispose(); _titleViewRenderer = null; } - _toolbar.RemoveView(_titleView); - _titleView = null; - _toolbar.RemoveView(_titleIconView); _titleIconView = null; _imageSource = null; - _toolbar.RemoveFromParent(); - _toolbar.SetNavigationOnClickListener(null); _toolbar = null; SetupToolbar(); diff --git a/Xamarin.Forms.Platform.Android/AppCompat/Platform.cs b/Xamarin.Forms.Platform.Android/AppCompat/Platform.cs index e64c048..5db46d6 100644 --- a/Xamarin.Forms.Platform.Android/AppCompat/Platform.cs +++ b/Xamarin.Forms.Platform.Android/AppCompat/Platform.cs @@ -21,7 +21,6 @@ namespace Xamarin.Forms.Platform.Android.AppCompat bool _disposed; bool _navAnimationInProgress; NavigationModel _navModel = new NavigationModel(); - Page _pendingRootChange = null; internal static string PackageName { get; private set; } internal static string GetPackageName() => PackageName ?? Android.Platform.PackageName; @@ -57,9 +56,9 @@ namespace Xamarin.Forms.Platform.Android.AppCompat return; _disposed = true; - SetPage(null); - FormsAppCompatActivity.BackPressed -= HandleBackPressed; + + SetPage(null); } void INavigation.InsertPageBefore(Page page, Page before) @@ -261,20 +260,22 @@ namespace Xamarin.Forms.Platform.Android.AppCompat { foreach (var rootPage in _navModel.Roots) { - if ((Android.Platform.GetRenderer(rootPage) is ILifeCycleState nr)) + if (Android.Platform.GetRenderer(rootPage) is ILifeCycleState nr) nr.MarkedForDispose = true; } - _pendingRootChange = newRoot; - // Queue up disposal of the previous renderers after the current layout updates have finished - new Handler(Looper.MainLooper).Post(() => - { - if (_pendingRootChange == newRoot) - { - _pendingRootChange = null; - SetPageInternal(newRoot); - } - }); + var viewsToRemove = new List(); + var renderersToDispose = new List(); + + for (int i = 0; i < _renderer.ChildCount; i++) + viewsToRemove.Add(_renderer.GetChildAt(i)); + + foreach (var root in _navModel.Roots) + renderersToDispose.Add(Android.Platform.GetRenderer(root)); + + SetPageInternal(newRoot); + + Cleanup(viewsToRemove, renderersToDispose); } else { @@ -298,17 +299,8 @@ namespace Xamarin.Forms.Platform.Android.AppCompat { var layout = false; - var viewsToRemove = new List(); - var renderersToDispose = new List(); - if (Page != null) { - for (int i = 0; i < _renderer.ChildCount; i++) - viewsToRemove.Add(_renderer.GetChildAt(i)); - - foreach (var root in _navModel.Roots) - renderersToDispose.Add(Android.Platform.GetRenderer(root)); - _navModel = new NavigationModel(); layout = true; @@ -316,32 +308,46 @@ namespace Xamarin.Forms.Platform.Android.AppCompat if (newRoot == null) { - Cleanup(viewsToRemove, renderersToDispose); + Page = null; + return; } _navModel.Push(newRoot, null); Page = newRoot; - AddChild(Page, layout); - Cleanup(viewsToRemove, renderersToDispose); + AddChild(Page, layout); Application.Current.NavigationProxy.Inner = this; } void Cleanup(List viewsToRemove, List renderersToDispose) { - for (int i = 0; i < viewsToRemove.Count; i++) + // If trigger by dispose, cleanup now, otherwise queue it for later + if (_disposed) { - AView view = viewsToRemove[i]; - _renderer?.RemoveView(view); + DoCleanup(); + } + else + { + new Handler(Looper.MainLooper).Post(DoCleanup); } - for (int i = 0; i < renderersToDispose.Count; i++) + void DoCleanup() { - IVisualElementRenderer rootRenderer = renderersToDispose[i]; - rootRenderer?.Dispose(); + for (int i = 0; i < viewsToRemove.Count; i++) + { + AView view = viewsToRemove[i]; + _renderer?.RemoveView(view); + } + + for (int i = 0; i < renderersToDispose.Count; i++) + { + IVisualElementRenderer rootRenderer = renderersToDispose[i]; + rootRenderer?.Element.ClearValue(Android.Platform.RendererProperty); + rootRenderer?.Dispose(); + } } } diff --git a/Xamarin.Forms.Platform.Android/AppCompat/ShellFragmentContainer.cs b/Xamarin.Forms.Platform.Android/AppCompat/ShellFragmentContainer.cs index dac210d..d77643c 100644 --- a/Xamarin.Forms.Platform.Android/AppCompat/ShellFragmentContainer.cs +++ b/Xamarin.Forms.Platform.Android/AppCompat/ShellFragmentContainer.cs @@ -1,4 +1,4 @@ -using Android.Content; +using Android.Content; using Android.OS; using Android.Runtime; using Android.Views; @@ -47,9 +47,9 @@ namespace Xamarin.Forms.Platform.Android.AppCompat public override void OnDestroy() { - base.OnDestroy(); - Device.BeginInvokeOnMainThread(Dispose); + + base.OnDestroy(); } } } \ No newline at end of file diff --git a/Xamarin.Forms.Platform.Android/AppCompat/TabbedPageRenderer.cs b/Xamarin.Forms.Platform.Android/AppCompat/TabbedPageRenderer.cs index c2a3610..c51315e 100644 --- a/Xamarin.Forms.Platform.Android/AppCompat/TabbedPageRenderer.cs +++ b/Xamarin.Forms.Platform.Android/AppCompat/TabbedPageRenderer.cs @@ -163,21 +163,22 @@ namespace Xamarin.Forms.Platform.Android.AppCompat if (disposing && !_disposed) { _disposed = true; - RemoveAllViews(); - foreach (Page pageToRemove in Element.Children) + + if (Element != null) { - IVisualElementRenderer pageRenderer = Android.Platform.GetRenderer(pageToRemove); - if (pageRenderer != null) + PageController.InternalChildren.CollectionChanged -= OnChildrenCollectionChanged; + + foreach (Page pageToRemove in Element.Children) { - pageRenderer.View.RemoveFromParent(); - pageRenderer.Dispose(); + TeardownPage(pageToRemove); } - pageToRemove.PropertyChanged -= OnPagePropertyChanged; - pageToRemove.ClearValue(Android.Platform.RendererProperty); } + RemoveAllViews(); + if (_viewPager != null) { + _viewPager.ClearOnPageChangeListeners(); _viewPager.Adapter.Dispose(); _viewPager.Dispose(); _viewPager = null; @@ -185,7 +186,7 @@ namespace Xamarin.Forms.Platform.Android.AppCompat if (_tabLayout != null) { - _tabLayout.AddOnTabSelectedListener(null); + _tabLayout.ClearOnTabSelectedListeners(); _tabLayout.Dispose(); _tabLayout = null; } @@ -204,7 +205,16 @@ namespace Xamarin.Forms.Platform.Android.AppCompat } if (Element != null) - PageController.InternalChildren.CollectionChanged -= OnChildrenCollectionChanged; + { + foreach (Page pageToRemove in Element.Children) + { + IVisualElementRenderer pageRenderer = Android.Platform.GetRenderer(pageToRemove); + + pageRenderer?.Dispose(); + + pageToRemove.ClearValue(Android.Platform.RendererProperty); + } + } _previousPage = null; } diff --git a/Xamarin.Forms.Platform.Android/CollectionView/ItemsViewRenderer.cs b/Xamarin.Forms.Platform.Android/CollectionView/ItemsViewRenderer.cs index 6703e78..0a64cfb 100644 --- a/Xamarin.Forms.Platform.Android/CollectionView/ItemsViewRenderer.cs +++ b/Xamarin.Forms.Platform.Android/CollectionView/ItemsViewRenderer.cs @@ -139,10 +139,7 @@ namespace Xamarin.Forms.Platform.Android if (Element != null) { TearDownOldElement(Element as ItemsView); - } - if (Element != null) - { if (Platform.GetRenderer(Element) == this) { Element.ClearValue(Platform.RendererProperty); diff --git a/Xamarin.Forms.Platform.Android/FastRenderers/AutomationPropertiesProvider.cs b/Xamarin.Forms.Platform.Android/FastRenderers/AutomationPropertiesProvider.cs index ecc9ab4..1841a3e 100644 --- a/Xamarin.Forms.Platform.Android/FastRenderers/AutomationPropertiesProvider.cs +++ b/Xamarin.Forms.Platform.Android/FastRenderers/AutomationPropertiesProvider.cs @@ -181,6 +181,11 @@ namespace Xamarin.Forms.Platform.Android.FastRenderers _disposed = true; + if (Element != null) + { + Element.PropertyChanged -= OnElementPropertyChanged; + } + if (_renderer != null) { _renderer.ElementChanged -= OnElementChanged; diff --git a/Xamarin.Forms.Platform.Android/FastRenderers/ButtonRenderer.cs b/Xamarin.Forms.Platform.Android/FastRenderers/ButtonRenderer.cs index 59ba49f..9c79ded 100644 --- a/Xamarin.Forms.Platform.Android/FastRenderers/ButtonRenderer.cs +++ b/Xamarin.Forms.Platform.Android/FastRenderers/ButtonRenderer.cs @@ -161,6 +161,12 @@ namespace Xamarin.Forms.Platform.Android.FastRenderers SetOnClickListener(null); SetOnTouchListener(null); RemoveOnAttachStateChangeListener(this); + OnFocusChangeListener = null; + + if (Element != null) + { + Element.PropertyChanged -= OnElementPropertyChanged; + } _automationPropertiesProvider?.Dispose(); _tracker?.Dispose(); @@ -172,8 +178,6 @@ namespace Xamarin.Forms.Platform.Android.FastRenderers if (Element != null) { - Element.PropertyChanged -= OnElementPropertyChanged; - if (Platform.GetRenderer(Element) == this) Element.ClearValue(Platform.RendererProperty); } diff --git a/Xamarin.Forms.Platform.Android/FastRenderers/FrameRenderer.cs b/Xamarin.Forms.Platform.Android/FastRenderers/FrameRenderer.cs index 21e20ce..06ec121 100644 --- a/Xamarin.Forms.Platform.Android/FastRenderers/FrameRenderer.cs +++ b/Xamarin.Forms.Platform.Android/FastRenderers/FrameRenderer.cs @@ -5,7 +5,6 @@ using Android.Graphics.Drawables; using Android.Support.V4.View; using Android.Support.V7.Widget; using Android.Views; -using Xamarin.Forms.Platform.Android.FastRenderers; using AColor = Android.Graphics.Color; using AView = Android.Views.View; @@ -115,6 +114,11 @@ namespace Xamarin.Forms.Platform.Android.FastRenderers if (disposing) { + if (Element != null) + { + Element.PropertyChanged -= OnElementPropertyChanged; + } + if (_visualElementTracker != null) { _visualElementTracker.Dispose(); @@ -133,8 +137,11 @@ namespace Xamarin.Forms.Platform.Android.FastRenderers _backgroundDrawable = null; } - _visualElementRenderer?.Dispose(); - _visualElementRenderer = null; + if (_visualElementRenderer != null) + { + _visualElementRenderer.Dispose(); + _visualElementRenderer = null; + } int count = ChildCount; for (var i = 0; i < count; i++) @@ -145,12 +152,9 @@ namespace Xamarin.Forms.Platform.Android.FastRenderers if (Element != null) { - Element.PropertyChanged -= OnElementPropertyChanged; - if (Platform.GetRenderer(Element) == this) Element.ClearValue(Platform.RendererProperty); } - } base.Dispose(disposing); diff --git a/Xamarin.Forms.Platform.Android/FastRenderers/ImageRenderer.cs b/Xamarin.Forms.Platform.Android/FastRenderers/ImageRenderer.cs index 76c8cf8..b468f9d 100644 --- a/Xamarin.Forms.Platform.Android/FastRenderers/ImageRenderer.cs +++ b/Xamarin.Forms.Platform.Android/FastRenderers/ImageRenderer.cs @@ -1,4 +1,4 @@ -using System; +using System; using System.ComponentModel; using System.Threading.Tasks; using Android.Content; @@ -32,6 +32,11 @@ namespace Xamarin.Forms.Platform.Android.FastRenderers if (disposing) { + if (_element != null) + { + _element.PropertyChanged -= OnElementPropertyChanged; + } + ImageElementManager.Dispose(this); BackgroundManager.Dispose(this); @@ -49,8 +54,6 @@ namespace Xamarin.Forms.Platform.Android.FastRenderers if (_element != null) { - _element.PropertyChanged -= OnElementPropertyChanged; - if (Platform.GetRenderer(_element) == this) _element.ClearValue(Platform.RendererProperty); } diff --git a/Xamarin.Forms.Platform.Android/FastRenderers/LabelRenderer.cs b/Xamarin.Forms.Platform.Android/FastRenderers/LabelRenderer.cs index 89acfcd..bbdcc6c 100644 --- a/Xamarin.Forms.Platform.Android/FastRenderers/LabelRenderer.cs +++ b/Xamarin.Forms.Platform.Android/FastRenderers/LabelRenderer.cs @@ -168,6 +168,11 @@ namespace Xamarin.Forms.Platform.Android.FastRenderers if (disposing) { + if (Element != null) + { + Element.PropertyChanged -= OnElementPropertyChanged; + } + BackgroundManager.Dispose(this); if (_visualElementTracker != null) { @@ -181,10 +186,11 @@ namespace Xamarin.Forms.Platform.Android.FastRenderers _visualElementRenderer = null; } + _spannableString?.Dispose(); + _labelTextColorDefault?.Dispose(); + if (Element != null) { - Element.PropertyChanged -= OnElementPropertyChanged; - if (Platform.GetRenderer(Element) == this) Element.ClearValue(Platform.RendererProperty); } diff --git a/Xamarin.Forms.Platform.Android/FastRenderers/VisualElementRenderer.cs b/Xamarin.Forms.Platform.Android/FastRenderers/VisualElementRenderer.cs index 4e8e609..5ae80ec 100644 --- a/Xamarin.Forms.Platform.Android/FastRenderers/VisualElementRenderer.cs +++ b/Xamarin.Forms.Platform.Android/FastRenderers/VisualElementRenderer.cs @@ -65,8 +65,10 @@ namespace Xamarin.Forms.Platform.Android.FastRenderers if (disposing) { - _gestureManager?.Dispose(); - _automationPropertiesProvider?.Dispose(); + if (Element != null) + { + Element.PropertyChanged -= OnElementPropertyChanged; + } if (_renderer != null) { @@ -74,6 +76,9 @@ namespace Xamarin.Forms.Platform.Android.FastRenderers _renderer.ElementPropertyChanged -= OnElementPropertyChanged; _renderer = null; } + + _gestureManager?.Dispose(); + _automationPropertiesProvider?.Dispose(); } } diff --git a/Xamarin.Forms.Platform.Android/Renderers/ShellSectionRenderer.cs b/Xamarin.Forms.Platform.Android/Renderers/ShellSectionRenderer.cs index b565c62..44689d2 100644 --- a/Xamarin.Forms.Platform.Android/Renderers/ShellSectionRenderer.cs +++ b/Xamarin.Forms.Platform.Android/Renderers/ShellSectionRenderer.cs @@ -1,4 +1,4 @@ -using Android.OS; +using Android.OS; using Android.Runtime; using Android.Support.Design.Widget; using Android.Support.V4.View; @@ -102,6 +102,7 @@ namespace Xamarin.Forms.Platform.Android IShellToolbarAppearanceTracker _toolbarAppearanceTracker; IShellToolbarTracker _toolbarTracker; ViewPager _viewPager; + NestedScrollView _scrollview; public ShellSectionRenderer(IShellContext shellContext) { @@ -126,7 +127,7 @@ namespace Xamarin.Forms.Platform.Android var root = inflater.Inflate(Resource.Layout.RootLayout, null).JavaCast(); _toolbar = root.FindViewById(Resource.Id.main_toolbar); - var scrollview = root.FindViewById(Resource.Id.main_scrollview); + _scrollview = root.FindViewById(Resource.Id.main_scrollview); _tablayout = root.FindViewById(Resource.Id.main_tablayout); _viewPager = new FormsViewPager(Context) @@ -149,7 +150,7 @@ namespace Xamarin.Forms.Platform.Android _toolbarTracker.Page = currentPage; _viewPager.CurrentItem = currentIndex; - scrollview.AddView(_viewPager); + _scrollview.AddView(_viewPager); if (shellSection.Items.Count == 1) { @@ -161,8 +162,6 @@ namespace Xamarin.Forms.Platform.Android HookEvents(); - scrollview.Dispose(); - return _rootView = root; } @@ -170,8 +169,6 @@ namespace Xamarin.Forms.Platform.Android // called before the animation completes. This causes tons of tiny issues. public override void OnDestroy() { - base.OnDestroy(); - if (_rootView != null) { UnhookEvents(); @@ -180,25 +177,29 @@ namespace Xamarin.Forms.Platform.Android _viewPager.Adapter = null; adapter.Dispose(); + _viewPager.RemoveOnPageChangeListener(this); + _scrollview.RemoveView(_viewPager); + _toolbarAppearanceTracker.Dispose(); _tabLayoutAppearanceTracker.Dispose(); - _viewPager.RemoveOnPageChangeListener(this); - _rootView.Dispose(); _toolbarTracker.Dispose(); - _tablayout.Dispose(); _toolbar.Dispose(); _viewPager.Dispose(); + _scrollview.Dispose(); _rootView.Dispose(); } _toolbarAppearanceTracker = null; _tabLayoutAppearanceTracker = null; _toolbarTracker = null; - _toolbar = null; _tablayout = null; - _rootView = null; + _toolbar = null; _viewPager = null; + _scrollview = null; + _rootView = null; + + base.OnDestroy(); } protected virtual void OnAnimationFinished(EventArgs e) diff --git a/Xamarin.Forms.Platform.Android/VisualElementPackager.cs b/Xamarin.Forms.Platform.Android/VisualElementPackager.cs index de091ca..8804481 100644 --- a/Xamarin.Forms.Platform.Android/VisualElementPackager.cs +++ b/Xamarin.Forms.Platform.Android/VisualElementPackager.cs @@ -72,6 +72,18 @@ namespace Xamarin.Forms.Platform.Android if (_renderer != null) { + _renderer.ElementChanged -= OnElementChanged; + + if (_renderer.Element != null) + { + _renderer.Element.ChildAdded -= _childAddedHandler; + _renderer.Element.ChildRemoved -= _childRemovedHandler; + _renderer.Element.ChildrenReordered -= _childReorderedHandler; + } + + if (_renderer.View is ILayoutChanges layout) + layout.LayoutChange -= OnInitialLayoutChange; + if (_childViews != null) { _childViews.Clear(); @@ -87,18 +99,6 @@ namespace Xamarin.Forms.Platform.Android _childPackagers = null; } - _renderer.ElementChanged -= OnElementChanged; - if (_renderer.Element != null) - { - _renderer.Element.ChildAdded -= _childAddedHandler; - _renderer.Element.ChildRemoved -= _childRemovedHandler; - - _renderer.Element.ChildrenReordered -= _childReorderedHandler; - } - - if (_renderer.View is ILayoutChanges layout) - layout.LayoutChange -= OnInitialLayoutChange; - _renderer = null; } diff --git a/Xamarin.Forms.Platform.Android/VisualElementRenderer.cs b/Xamarin.Forms.Platform.Android/VisualElementRenderer.cs index ce127b3..94b9eaa 100644 --- a/Xamarin.Forms.Platform.Android/VisualElementRenderer.cs +++ b/Xamarin.Forms.Platform.Android/VisualElementRenderer.cs @@ -62,7 +62,7 @@ namespace Xamarin.Forms.Platform.Android } return base.DispatchTouchEvent(e); - } + } [Obsolete("This constructor is obsolete as of version 2.5. Please use VisualElementRenderer(Context) instead.")] [EditorBrowsable(EditorBrowsableState.Never)] @@ -202,11 +202,8 @@ namespace Xamarin.Forms.Platform.Android public void SetElement(TElement element) { - if (element == null) - throw new ArgumentNullException(nameof(element)); - TElement oldElement = Element; - Element = element; + Element = element ?? throw new ArgumentNullException(nameof(element)); Performance.Start(out string reference); @@ -215,13 +212,10 @@ namespace Xamarin.Forms.Platform.Android oldElement.PropertyChanged -= _propertyChangeHandler; } - // element may be allowed to be passed as null in the future - if (element != null) - { - Color currentColor = oldElement != null ? oldElement.BackgroundColor : Color.Default; - if (element.BackgroundColor != currentColor) - UpdateBackgroundColor(); - } + Color currentColor = oldElement?.BackgroundColor ?? Color.Default; + + if (element.BackgroundColor != currentColor) + UpdateBackgroundColor(); if (_propertyChangeHandler == null) _propertyChangeHandler = OnElementPropertyChanged; @@ -241,15 +235,14 @@ namespace Xamarin.Forms.Platform.Android if (AutoTrack && Tracker == null) SetTracker(new VisualElementTracker(this)); - if (oldElement != null && element != null) + if (oldElement != null) Tracker?.UpdateLayout(); - if (element != null) - SendVisualElementInitialized(element, this); + SendVisualElementInitialized(element, this); EffectUtilities.RegisterEffectControlProvider(this, oldElement, element); - if (element != null && !string.IsNullOrEmpty(element.AutomationId)) + if (!string.IsNullOrEmpty(element.AutomationId)) SetAutomationId(element.AutomationId); SetContentDescription(); @@ -285,6 +278,11 @@ namespace Xamarin.Forms.Platform.Android EffectUtilities.UnregisterEffectControlProvider(this, Element); + if (Element != null) + { + Element.PropertyChanged -= _propertyChangeHandler; + } + if (Tracker != null) { Tracker.Dispose(); @@ -315,8 +313,6 @@ namespace Xamarin.Forms.Platform.Android if (Element != null) { - Element.PropertyChanged -= _propertyChangeHandler; - if (Platform.GetRenderer(Element) == this) Platform.SetRenderer(Element, null); @@ -346,7 +342,7 @@ namespace Xamarin.Forms.Platform.Android ElevationHelper.SetElevation(this, e.NewElement); } - + protected virtual void OnElementPropertyChanged(object sender, PropertyChangedEventArgs e) { if (e.PropertyName == VisualElement.BackgroundColorProperty.PropertyName) @@ -381,7 +377,8 @@ namespace Xamarin.Forms.Platform.Android static void UpdateLayout(IEnumerable children) { - foreach (Element element in children) { + foreach (Element element in children) + { var visualElement = element as VisualElement; if (visualElement == null) continue; -- 2.7.4