I need to understand how to use MvxCachingFragmentCompatActivity. I have asked this question before previous question, but I got a piece of example code, which is helpful but not what I needed. What I need is an understanding of how to use it.
First of all I have one activity and all my views are fragments.
My big assumption here is that using MvxCachingFragmentCompatActivity will enable me to restore my application navigation hierarchy if my activity is torn down and needs to be restored. Can someone confirm if this is correct.
If this is correct how do I use it. For example
- Do I need to implement Save and Restore state in the view models? Is there anything else the developer needs to do?
- What does the MvxFragmentAttribute parameter IsCacheableFragment actually do as regards caching fragments?
- What performs the action of recreating my fragment hierarchy when an activity is restored?
It would be great if there was some documentation around this.
I need to know this as my Activity is being torn down and then restored after I use another Activity for a camera feature. When the Activity restores itself the ViewModel for my fragments are null.Also I am finding Close(this) does not work in my view model. I'm sure I am not doing everything I need to do to make this work, but I need guidance on how it is supposed to be used.
Any help would be appreciated, maybe someone from the MvvmCross team. I'm really stuck here. I would prefer a description of the behaviour rather than point to a sample, but both would be great.
[Updated] So I built a debug version of the V4 and V7 MvvmCross libraries and set about debugging. As far as I can tell as long as you add the following attributes to your fragment class this should set about caching your fragments.
[MvxFragment(typeof(MainActivityViewModel), Resource.Id.contentFrame, AddToBackStack = true, IsCacheableFragment = true)]
[Register("com.dummynamespace.MyFragment")]
Note the lowercase namespace is important, your class name can be mixed case.
However I am still seeing problems after my activity is destroyed and re-created. In my case I am actually seeing my activity destroyed and recreated more than once in quick succession. One example is that I cannot close the view after the activity destroyed and recreated. This seems to be due to the fact that the code in GetFragmentInfoByTag (MvxCachingFragmentCompatActivity class) is returning the wrong information needed to close the view. The close functionality needs the ContentId from the returned IMvxCachedFragmentInfo, however this is returning it as 0. Also the AddToBackStack property is set to false. Below I have listed what is returned in the fragment info
AddToBackStack = false
CacheFragment = true
CachedFragment = null
ContentId = 0
FragmentType = This is set to the correct fragment type
Tag = This is set to the corresponding view model for the fragment
Before the activity is destroyed and recreated the the fragment info is correct.
I am using MvvmCross 4.2.3. Has anyone else experience this?
Update 02/03/2017 I found out that my activity was being destroyed and recreated not due to memory but due to the camera orientation. We found it only failed when we held the camera in landscape mode.
The issue regarding the ContentId being set to 0 was caused by my app not being able to resolve the IMvxJsonConverter implemenation. This occurs when the MvvmCross Json plugin is not installed. Also you have to add the following to your App.cs file so it can be registered
Mvx.RegisterType<IMvxJsonConverter, MvxJsonConverter>();
If this is not done, then the Try.Resolve fails and the code that uses it is skipped over. Sometimes it is done silently other times it outputs a log. IT would seem to me that this should probably be fatal if you expect your app to survive the activoty being torn down and reconstructed.
Also one the MvvmCross Json plugin is installed you have to implement the Save and Restore state pattern in your view models save-Restore
Update new problem 08/03/2017 I am testing the restore of every view in my app. I am doing this by allowing the orientation to be changed which destroys my MvxCachingFragmentCompatActivity and then re-creates it.
When the activity is destroyed my fragment is also destroyed. At this point I tidy up my view model to ensure it will be free'd up and will not cause a memory leak.
However I have hit a problem where when OnCreate is called. It seems to do two things
- Get a view model from the MvxFragmentExtensions OnCreate method by calling into the view model cache
- Then calls RestoreViewModelsFromBundle
The problem is that the call to MvxFragmentExtensions OnCreate (1) calls into the view model cache and returns a view model which has not been Started e.g Start() called on it, but this is used to set the DataContext.
After RestoreViewModelsFromBundle (2) is called the DataContext is not set again event though it has gone through the Constructor->Init->RestoreState->Start set up. So I now have a view model which is not setup properly and so my view does not work.
When I took out my code to tidy the view models, I got a bit further as the cached view model set by (1) now had the correct data. But I am hitting other problems because it is attempting to create a new view model due to the call to RestoreViewModelsFromBundle (2). As a short term fix is there anyway I can force the view model created as part of the restore process to be set as the ViewModel
Can someone from the MvvmCross team please help out with some information as to what is happening here and why?