Example of how to use MvxCachingFragmentActivity
Asked Answered
S

1

0

Update - Thanks to @Martijn00 and @Plac3Hold3r I have managed to update my app to use the MvxCachingFragmentCompatActivity but it is just not working correctly. I am finding that if I go back sometimes the the ViewModel will be available, but the commands in the view model will be null.

Also if I go back and then forward, some of the buttons don't respond. I assume this is the same issue.

What I really need to know is what the additional functionality the caching activity gives me, and how to use it properly.

Original question follows...

I am hitting a problem where the view model for a fragment is null. I suspect my activity is being cleared up when I open a camera activity. For all my application am using a single activity and all my views are fragments.

When the camera activity is complete, the activity is reconstructed, but one of the fragments view model is null. I am currently using an AppCompatActivity for my single activity, but through my research I should probably be using a MvxCachingFragmentActivity. The problem is I have no idea how I am supposed to use it. I cannot find a clear explanation anywhere.

Has anyone got a working example of how to use the MvxCachingFragmentActivity or the MvxCachingFragmentCompatActivity.

I can't find anywhere where it tells me how I should use it.

I found this other link example but I think it is out of date and the other link given in this example is a 404.

If anyone knows of a simple sample and whether this will work with a single activity please let me know.

Thanks

Speaker answered 20/2, 2017 at 14:5 Comment(2)
It's now here: github.com/MvvmCross/MvvmCross/tree/develop/TestProjects/…Anastase
Hi Martin, Thanks for that. Still not sure what to do. Is it just a matter of setting my single activity to be a MvxCachingFragmentCompatActivity rather than an AppCompatActivity. I tried that with no luck still crashed when trying to reinstantiate the activity. I have a custom presenter, in this case do I have to do anything else. Is there any good articles that explain what should happen? Sorry to be a pain.Speaker
D
3

Setup

MainActivity

Create an activity that inherits from MvxCachingFragmentCompatActivity or MvxCachingFragmentActivity.

[Activity]
public class MainActivity : BaseFragmentActivity<MainContainerViewModel>
{
}

MainContainerViewModel

Create a Viewmodel to associate to the Activity. You will never navigate directly using this Viewmodel. Instead you will navigate to this Viewmodel via the fragments that specifies MainContainerViewModel as their parent's Viewmodel.

public class MainContainerViewModel : MvxViewModel
{
}

XML layout example

Add a layout to your MainActivity. Make sure to include a FrameLayout that has an id. In this case content_frame. This id is important as this is how you will identify the frame where to place your fragment. You specify multiple FrameLayout's if you want more that one fragment for the same view.

<?xml version="1.0" encoding="utf-8"?>
<android.support.design.widget.CoordinatorLayout
  xmlns:android="http://schemas.android.com/apk/res/android"
  android:id="@+id/coordinator_layout"
  android:layout_width="match_parent"
  android:layout_height="match_parent">

  <LinearLayout
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:orientation="vertical">

    <android.support.design.widget.AppBarLayout
        android:id="@+id/appbar"
        android:layout_width="match_parent"
        android:layout_height="?attr/actionBarSize"
        android:theme="@style/ThemeOverlay.AppCompat.Dark.ActionBar">

      <android.support.v7.widget.Toolbar
          android:id="@+id/toolbar"
          android:layout_width="match_parent"
          android:layout_height="?attr/actionBarSize"
          android:background="?attr/colorPrimary">

        <TextView
            android:id="@+id/textview_toolbar_title"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:textColor="@android:color/white"
            android:layout_gravity="left"
            style="@style/TextAppearance.AppCompat.Widget.ActionBar.Title" />

      </android.support.v7.widget.Toolbar>

    </android.support.design.widget.AppBarLayout>

      <FrameLayout
        android:id="@+id/content_frame"
        android:layout_width="match_parent"
        android:layout_height="wrap_content" />

  </LinearLayout>

</android.support.design.widget.CoordinatorLayout>

HomeFragment

In terms of fragments you need to include the MvxFragment attribute, which needs the type of Viewmodel associate to the Activity you want to place your fragment in. Additionally, you need to specify the id for the FrameLayout that is found on the activities layout, where you want to place the fragment.

[MvxFragment(typeof(MainContainerViewModel), Resource.Id.content_frame)]
[Register(nameof(HomeFragment))]
public class HomeFragment : BaseFragment<HomeViewModel>
{
}

Usage

When navigating your can now use ShowViewModel<HomeViewModel>() which will navigate to the home fragment. But, importantly it will first start up the required Activity MainActivity before doing the fragment navigation. This allows for better shared navigation with other platforms which do not require these container Viewmodels, i.e. they get handled automatically via convention.


Notes

You can specify multiple MvxFragment attributes. Is is usefully if you want the same fragment shared under multiple Activities. The Top MvxFragment attribute will be used as the default. If you are currently in the context of any of the other matching MvxFragment attributes then navigation will take place under that activity.

If your Setup.cs is not inheriting from MvxAppCompatSetup or you are using a custom presenter, you need to make sure that you also registering your presenter against IMvxAndroidViewPresenter. This is important as MvxCachingFragmentCompatActivity or MvxCachingFragmentActivity resolve IMvxAndroidViewPresenter in order to navigate to the required fragment.

protected override IMvxAndroidViewPresenter CreateViewPresenter()
{
    var mvxFragmentsPresenter = new MvxFragmentsPresenter(AndroidViewAssemblies);
    Mvx.RegisterSingleton<IMvxAndroidViewPresenter>(mvxFragmentsPresenter);
    return mvxFragmentsPresenter;
}

You can also check out the Sample Repo for an example of this in use.

Delgado answered 21/2, 2017 at 20:15 Comment(7)
(1) Thanks Plac3Hold3r. This is useful, but this is not the part I don't understand. The bit that I do not understand is the caching part of the MvxCachingFragmentActivity or the MvxCachingFragmentCompatActivity. My understanding is that if the app's activity is needs to be reconstructed due to the platform previously needing the resources, then the caching aspect of these activity types provides the functionality to cache the fragments and reconstruct the fragments when the activity is reconstructed.Speaker
(2) Currently what is happening is that one of my fragments view model is null when the activity is reconstructed. What I need to know is whether I need to do anything to make this caching feature work. If so what do I need to do?Speaker
If you add protected override void ShowFragment(string tag, int contentId, Bundle bundle, bool forceAddToBackStack = false, bool forceReplaceFragment = false) { base.ShowFragment(tag, contentId, bundle, forceAddToBackStack, true); } to your MvxCachingFragmentActivity does it still occur? This code can be used to force a refresh of the fragment and viewmodel.Delgado
I think the issue for me is that I don't know how the caching is supposed to work behind the scenes to know what is going wrong.Speaker
I have set up my application as per your sample application but when the app is starting I get the following exception - Any ideas Exception masked ArgumentException: An item with the same key has already been added.Speaker
In the logs I get the message "howing ViewModel MainActivityViewModel", then I get the exception Exception masked ArgumentException: An item with the same key has already been added. I am not hitting the MainActivity or the MainActivityViewModel. I have removed my CustomViewPresenter to simplify the setup, but I still get the same issue. Any ideas? The stack trace is in MvxFragmentsPresenter.Show - FragmentHostRegistrationSettings.IsTypeRegisteredAsAFragment - FragmentHostRegistrationSettings.InitializeIfNeededSpeaker
Ok, found the answer to the comment above about the exception relating to having the same key. The answer can be found here #41802461Speaker

© 2022 - 2024 — McMap. All rights reserved.