Skip to content
This repository has been archived by the owner. It is now read-only.

#275 Correct fragment tracking for correct GetLastFragmentInfo in MvxCachingFragmentCompatActivity #297

Open
wants to merge 1 commit into
base: master
Choose a base branch
from
Open
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
Expand Up @@ -17,7 +17,6 @@
using MvvmCross.Platform;
using MvvmCross.Platform.Exceptions;
using MvvmCross.Platform.Platform;
using MvvmCross.Binding.Droid.BindingContext;
using MvvmCross.Droid.Platform;
using MvvmCross.Droid.Views;
using MvvmCross.Core.ViewModels;
Expand All @@ -26,6 +25,7 @@
using MvvmCross.Droid.Shared.Presenter;
using MvvmCross.Droid.Shared.Attributes;
using MvvmCross.Droid.Shared.Fragments;
using MvvmCross.Droid.Support.V4;

namespace MvvmCross.Droid.Support.V7.AppCompat
{
Expand All @@ -34,7 +34,10 @@ public class MvxCachingFragmentCompatActivity : MvxAppCompatActivity, IFragmentC
{
public const string ViewModelRequestBundleKey = "__mvxViewModelRequest";
private const string SavedFragmentTypesKey = "__mvxSavedFragmentTypes";
private const string SavedTagBackStack = "__mvxSavedTagBackStack";

private IFragmentCacheConfiguration _fragmentCacheConfiguration;
private readonly Stack<string> _tagBackStack = new Stack<string>();

public override View OnCreateView(View parent, string name, Context context, IAttributeSet attrs)
{
Expand Down Expand Up @@ -119,6 +122,21 @@ private void RestoreFragmentsCache()
}
}

private void RestoreTagBackStackFromBundle(IMvxJsonConverter serializer, Bundle savedInstanceState)
{
var savedTagBackStackJson = savedInstanceState.GetString(SavedTagBackStack);
if (!string.IsNullOrEmpty(savedTagBackStackJson))
{
var savedReversedTagBackStackState = serializer.DeserializeObject<string[]>(savedTagBackStackJson);

_tagBackStack.Clear();
for (int i = 0; i < savedReversedTagBackStackState.Length; i++)
{
_tagBackStack.Push(savedReversedTagBackStackState[i]);
}
}
}

private Dictionary<string, Type> CreateFragmentTypesDictionary(Bundle outState)
{
IMvxSavedStateConverter savedStateConverter;
Expand Down Expand Up @@ -157,7 +175,19 @@ protected override void OnSaveInstanceState(Bundle outState)
{
base.OnSaveInstanceState(outState);
IMvxJsonConverter ser;
if (FragmentCacheConfiguration.HasAnyFragmentsRegisteredToCache && Mvx.TryResolve(out ser))
if (!Mvx.TryResolve(out ser))
{
return;
}

if (_tagBackStack.Any())
{
var reversedTagBackStack = _tagBackStack.Reverse().ToArray();
var json = ser.SerializeObject(reversedTagBackStack);
outState.PutString(SavedTagBackStack, json);
}

if (FragmentCacheConfiguration.HasAnyFragmentsRegisteredToCache)
{
FragmentCacheConfiguration.SaveFragmentCacheConfigurationState(outState, ser);

Expand Down Expand Up @@ -208,9 +238,10 @@ protected virtual void ShowFragment(string tag, int contentId, Bundle bundle, bo
//If we already have a previously created fragment, we only need to send the new parameters
if (fragInfo.CachedFragment != null && fragmentReplaceMode == FragmentReplaceMode.ReplaceFragment)
{
(fragInfo.CachedFragment as Fragment).Arguments.Clear();
(fragInfo.CachedFragment as Fragment).Arguments.PutAll(bundle);
}
var fragment = fragInfo.CachedFragment.ToFragment();
fragment.Arguments.Clear();
fragment.Arguments.PutAll(bundle);
}
else
{
//Otherwise, create one and cache it
Expand All @@ -222,6 +253,8 @@ protected virtual void ShowFragment(string tag, int contentId, Bundle bundle, bo
currentFragment = fragInfo.CachedFragment as Fragment;
ft.Replace(fragInfo.ContentId, fragInfo.CachedFragment as Fragment, fragInfo.Tag);

_tagBackStack.Push(fragInfo.Tag);

//if replacing ViewModel then clear the cache after the fragment
//has been added to the transaction so that the Tag property is not null
//and the UniqueImmutableCacheTag property (if not overridden) has the correct value
Expand Down Expand Up @@ -277,6 +310,9 @@ public override void OnBackPressed()
{
if (SupportFragmentManager.BackStackEntryCount >= 1)
{
var backStackEntry = SupportFragmentManager.GetBackStackEntryAt(SupportFragmentManager.BackStackEntryCount - 1);
RemoveFromTagBackStack(backStackEntry.Name);

SupportFragmentManager.PopBackStackImmediate();

if (FragmentCacheConfiguration.EnableOnFragmentPoppedCallback)
Expand All @@ -289,6 +325,7 @@ public override void OnBackPressed()
return;
}

_tagBackStack.Clear();
base.OnBackPressed();
}

Expand All @@ -311,12 +348,12 @@ protected virtual IEnumerable<Fragment> GetCurrentCacheableFragments()

protected virtual IMvxCachedFragmentInfo GetLastFragmentInfo()
{
var currentCacheableFragments = GetCurrentCacheableFragments().ToList();
if (!currentCacheableFragments.Any())
if (!_tagBackStack.Any())
{
throw new InvalidOperationException("Cannot retrieve last fragment as FragmentManager is empty.");
}

var lastFragment = currentCacheableFragments.Last();
var tagFragment = GetTagFromFragment(lastFragment);
var tagFragment = _tagBackStack.Peek();

return GetFragmentInfoByTag(tagFragment);
}
Expand Down Expand Up @@ -351,7 +388,9 @@ protected override void OnCreate (Bundle bundle)
return;
}

FragmentCacheConfiguration.RestoreCacheConfiguration(bundle, serializer);
RestoreTagBackStackFromBundle(serializer, bundle);

FragmentCacheConfiguration.RestoreCacheConfiguration(bundle, serializer);
// Gabriel has blown his trumpet. Ressurect Fragments from the dead.
RestoreFragmentsCache();

Expand Down Expand Up @@ -389,6 +428,7 @@ protected virtual void CloseFragment(string tag, int contentId)
var frag = SupportFragmentManager.FindFragmentById(contentId);
if (frag == null) return;

RemoveFromTagBackStack(frag.Tag);
SupportFragmentManager.PopBackStackImmediate(tag, 1);
}

Expand Down Expand Up @@ -456,6 +496,7 @@ public virtual bool Close(IMvxViewModel viewModel)
{
if (SupportFragmentManager.BackStackEntryCount == 0)
{
_tagBackStack.Clear();
base.OnBackPressed();
return true;
}
Expand All @@ -471,6 +512,24 @@ public virtual bool Close(IMvxViewModel viewModel)
CloseFragment(frag.Tag, frag.ContentId);
return true;
}

private void RemoveFromTagBackStack(string tag)
{
// reverse to more logical order
var tagBackStack = _tagBackStack.Reverse().ToList();

// remove tag
var firstFoundTagIndex = tagBackStack.FindIndex(backStackTag => backStackTag == tag);
if (firstFoundTagIndex > 0)
tagBackStack.RemoveAt(firstFoundTagIndex);

// hard reset and reinitialize _tagBackStack
_tagBackStack.Clear();
for (var i = 0; i < tagBackStack.Count; i++)
{
_tagBackStack.Push(tagBackStack[i]);
}
}
}

public abstract class MvxCachingFragmentCompatActivity<TViewModel>
Expand Down