Search code examples
c#androidandroid-fragmentsxamarin.androidmvvmcross

Cant find class for fragment.inflate


I'm implementing a tabbed view using a ViewPager in my android application using this tutorial http://blog.ostebaronen.dk/2013/07/fragments-and-viewpager-with-mvx.html.

After doing everything told there, android throws an exception when it tries to inflate the fragment

Unable to instantiate fragment moviehall.client.android.views.fragments.AllMoviesView: make sure class name exists, is public, and has an empty constructor that is public.

After some research, all places I found implied the problem was in the java not detecting the namespaces in uppercase, but as you can see in the error, it is correctly cased. What am I missing?

Here's the code I use to inflate the fragments:

public override Fragment GetItem(int position)
{
    var frag = Fragments.ElementAt(position);
    var fragment = Fragment.Instantiate(_context,
        FragmentJavaName(frag.FragmentType));
    ((MvxFragment)fragment).DataContext = frag.ViewModel;
    return fragment;
}

here's the FragmentInfo class

public class FragmentInfo
{
    public string Title { get; set; }
    public Type FragmentType { get; set; }
    public IMvxViewModel ViewModel { get; set; }
}

And this is the method i use to put convert the namespaces to lowercase

protected virtual string FragmentJavaName(Type fragmentType)
{
    var namespaceText = fragmentType.Namespace ?? "";
    if (namespaceText.Length > 0)
        namespaceText = namespaceText.ToLowerInvariant() + ".";
    return namespaceText + fragmentType.Name;
}

Finally, this is the class that it can't find

namespace MovieHall.Client.Android.Views.Fragments
{    
    [Activity(Label = "Movies")]
    public class AllMoviesView : MvxFragment
    {
        public override View OnCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState)
        {
            var ignore =  base.OnCreateView(inflater, container, savedInstanceState);
            return this.BindingInflate(Resource.Layout.all_movies, null);
        }
    }
}

Solution

  • As of Xamarin Android 5.0, there is a breaking change in how names are defined. For more info, see: https://developer.xamarin.com/releases/android/xamarin.android_5/xamarin.android_5.0/#Android_Callable_Wrapper_Naming

    What you need to do is specify the actual name you want to define on the Java side. Use the Register attribute.

    namespace MovieHall.Client.Android.Views.Fragments
    {    
        [Register("moviehall.client.android.views.fragments.AllMoviesView")]
        public class AllMoviesView : MvxFragment
        {
            public override View OnCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState)
            {
                var ignore =  base.OnCreateView(inflater, container, savedInstanceState);
                return this.BindingInflate(Resource.Layout.all_movies, null);
            }
        }
    }
    

    NOTE: I'm not sure why you used the Activity attribute as this is a fragment.