[Android] Fix MasterDetailContainer fragment handling (#6471)
authorKevin Petit <kevin.petit@outlook.com>
Thu, 22 Aug 2019 14:00:13 +0000 (16:00 +0200)
committerRui Marinho <me@ruimarinho.net>
Thu, 22 Aug 2019 14:00:13 +0000 (15:00 +0100)
* Fix MasterDetailContainer fragment handling.
Transaction is necessarily executed after the view is added.

* Only postpone the transaction if the view is not attached yet.

* typo, private

Xamarin.Forms.Platform.Android/AppCompat/MasterDetailContainer.cs
Xamarin.Forms.Platform.Android/Extensions/FragmentManagerExtensions.cs

index 9670dc8..8696f2b 100644 (file)
@@ -1,14 +1,12 @@
-using System;
 using Android.App;
 using Android.Content;
-using Android.OS;
 using Fragment = Android.Support.V4.App.Fragment;
 using FragmentManager = Android.Support.V4.App.FragmentManager;
 using FragmentTransaction = Android.Support.V4.App.FragmentTransaction;
 
 namespace Xamarin.Forms.Platform.Android.AppCompat
 {
-       internal class MasterDetailContainer : Xamarin.Forms.Platform.Android.MasterDetailContainer, IManageFragments
+       internal class MasterDetailContainer : Android.MasterDetailContainer, IManageFragments
        {
                PageContainer _pageContainer;
                FragmentManager _fragmentManager;
@@ -16,6 +14,7 @@ namespace Xamarin.Forms.Platform.Android.AppCompat
                MasterDetailPage _parent;
                Fragment _currentFragment;
                bool _disposed;
+               FragmentTransaction _transaction;
 
                public MasterDetailContainer(MasterDetailPage parent, bool isMaster, Context context) : base(parent, isMaster, context)
                {
@@ -79,9 +78,10 @@ namespace Xamarin.Forms.Platform.Android.AppCompat
                                        transaction.RemoveEx(_currentFragment);
                                        transaction.SetTransitionEx((int)FragmentTransit.None);
 
-                                       // This is a removal of a fragment that's not going on the back stack; there's no reason to care
-                                       // whether its state gets successfully saved, since we'll never restore it. Ergo, CommitAllowingStateLoss
-                                       transaction.CommitAllowingStateLossEx();
+                                       if (IsAttachedToWindow)
+                                               ExecuteTransaction(transaction);
+                                       else
+                                               _transaction = transaction;
 
                                        _currentFragment = null;
                                }
@@ -114,14 +114,27 @@ namespace Xamarin.Forms.Platform.Android.AppCompat
                                transaction.AddEx(Id, fragment);
                                transaction.SetTransitionEx((int)FragmentTransit.None);
 
-                               // We don't currently support fragment restoration 
-                               // So we don't need to worry about loss of this fragment's state
-                               transaction.CommitAllowingStateLossEx();
+                               if (IsAttachedToWindow)
+                                       ExecuteTransaction(transaction);
+                               else
+                                       _transaction = transaction;
 
                                _currentFragment = fragment;
                        }
                }
 
+               protected override void OnAttachedToWindow()
+               {
+                       base.OnAttachedToWindow();
+
+                       if (_transaction == null)
+                               return;
+
+                       ExecuteTransaction(_transaction);
+
+                       _transaction = null;
+               }
+
                protected override void Dispose(bool disposing)
                {
                        if (_disposed)
@@ -157,5 +170,16 @@ namespace Xamarin.Forms.Platform.Android.AppCompat
                        if (_fragmentManager == null)
                                _fragmentManager = fragmentManager;
                }
+
+               void ExecuteTransaction(FragmentTransaction transaction)
+               {
+                       // We don't currently support fragment restoration 
+                       // So we don't need to worry about loss of this fragment's state
+                       transaction.CommitAllowingStateLossEx();
+
+                       // The transaction need to be executed after View has been attached
+                       // So Fragment Manager can find the View being added
+                       FragmentManager.ExecutePendingTransactionsEx();
+               }
        }
 }
\ No newline at end of file
index fc3b585..8fd0218 100644 (file)
@@ -1,4 +1,4 @@
-using FragmentTransaction = Android.Support.V4.App.FragmentTransaction;
+using FragmentTransaction = Android.Support.V4.App.FragmentTransaction;
 using Fragment = Android.Support.V4.App.Fragment;
 using FragmentManager = Android.Support.V4.App.FragmentManager;
 
@@ -37,14 +37,14 @@ namespace Xamarin.Forms.Platform.Android
                        return fragmentTransaction.CommitAllowingStateLoss();
                }
 
-               public static bool ExecutePendingTransactionsEx(this FragmentManager fragmentTransaction)
+               public static bool ExecutePendingTransactionsEx(this FragmentManager fragmentManager)
                {
-                       return fragmentTransaction.ExecutePendingTransactions();
+                       return fragmentManager.ExecutePendingTransactions();
                }
 
-               public static FragmentTransaction BeginTransactionEx(this FragmentManager fragmentTransaction)
+               public static FragmentTransaction BeginTransactionEx(this FragmentManager fragmentManager)
                {
-                       return fragmentTransaction.BeginTransaction();
+                       return fragmentManager.BeginTransaction();
                }
        }
 }
\ No newline at end of file