Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

InstantiationException: Unable to instantiate fragment make sure class name exists, is public, and has an empty constructor that is public

I have a project that I originally developed using Android Studio. I decided to convert it to Xamarin (Visual Studio 2015).

After hours of porting all the code over, everything works except for my Settings activity (PreferenceActivity). I have a few PreferenceFragments that make up the settings, but all of them give me "Unable to instantiate fragment". Here is the exception I am getting:

Java.Lang.RuntimeException: Unable to start activity ComponentInfo{test.mypackagename/md50d00e677e41fc49f8b3c16e79df2b77f.SettingsActivity}: android.app.Fragment$InstantiationException: Unable to instantiate fragment test.mypackagename.GeneralPreferenceFragment: make sure class name exists, is public, and has an empty constructor that is public

I have been looking online for a solution but I just cant seem to find one. Everywhere I look they say make sure there is an empty public constructor, if its an inner class it has to be static. But I have the empty constructor and its not an inner class, its in its own file.

Here is my SettingsActivity.cs:

namespace test.mypackagename
{
    public class SettingsActivity : PreferenceActivity
    {
        protected override void OnPostCreate(Bundle savedInstanceState)
        {
            base.OnPostCreate(savedInstanceState);
        }

        public override void OnBuildHeaders(IList<Header> target)
        {
            LoadHeadersFromResource(Resource.Xml.pref_headers, target);
        }
    }
}

Here is my GeneralPreferenceFragment.cs:

namespace test.mypackagename
{
    public class GeneralPreferenceFragment : PreferenceFragment
    {
        public GeneralPreferenceFragment() { }

        public override void OnCreate(Bundle savedInstanceState)
        {
            base.OnCreate(savedInstanceState);
            AddPreferencesFromResource(Resource.Xml.pref_general);
        }
    }
}

And here is my pref_headers.xml:

<preference-headers xmlns:android="http://schemas.android.com/apk/res/android">

    <header android:fragment="test.mypackagename.GeneralPreferenceFragment"
        android:title="@string/pref_header_general" />

    <header android:fragment="test.mypackagename.OtherPreferenceFragment1"
        android:title="@string/pref_header_other1" />

    <header android:fragment="test.mypackagename.OtherPreferenceFragment2"
        android:title="@string/pref_header_other2" />

    <header android:fragment="test.mypackagename.OtherPreferenceFragment3"
        android:title="@string/pref_header_other3" />

    <header android:fragment="test.mypackagename.OtherPreferenceFragment4"
        android:title="@string/pref_header_other4" />

</preference-headers>

This was working fine before so Im not sure what the issue could be. Any help would be much appreciated.

like image 609
Brian Tacker Avatar asked Apr 05 '16 20:04

Brian Tacker


1 Answers

I think you are running into this problem because when not using the [Register] attribute on your PreferenceFragment then its name appended with a MD5 sum by Xamarin.

So in order to actually have the namespace you expect it to in the pref_headers.xml you need to attribute your class:

[Register("test.mypackagename.GeneralPreferenceFragment")]
public class GeneralPreferenceFragment: PreferenceFragment
{
    // code here
}

EDIT:

I've just tested the code and it works fine on my machine. I am not using any support packages or anything.

pref_general.xml

<?xml version="1.0" encoding="utf-8" ?> 
<PreferenceScreen
        xmlns:android="http://schemas.android.com/apk/res/android">
    <PreferenceCategory
            android:title="durr">
        <CheckBoxPreference
                android:key="checkbox_preference"
                android:title="herp"
                android:summary="derp" />
    </PreferenceCategory>
</PreferenceScreen>

pref_headers.xml

<?xml version="1.0" encoding="utf-8" ?>
<preference-headers xmlns:android="http://schemas.android.com/apk/res/android">
  <header android:fragment="test.mypackagename.GeneralPreferenceFragment"
      android:title="general" />
</preference-headers>

SettingsActivity.cs

[Activity(Label = "SettingsActivity")]
public class SettingsActivity : PreferenceActivity
{
    public override void OnBuildHeaders(IList<Header> target)
    {
        LoadHeadersFromResource(Resource.Xml.pref_headers, target);
    }
}

GeneralPreferenceFragment.cs

[Register("test.mypackagename.GeneralPreferenceFragment")]
public class GeneralPreferenceFragment : PreferenceFragment
{
    public override void OnCreate(Bundle savedInstanceState)
    {
        base.OnCreate(savedInstanceState);

        AddPreferencesFromResource(Resource.Xml.pref_general);
    }
}

This works fine and the app shows up the SettingsActivity with first a general option, after clicking on that it shows up a Title and CheckBox.

General CheckBoxPreference

This worked even without providing any ctor to the GeneralPreferenceFragment. However, you could try add these:

public GeneralPreferenceFragment()
{
}

public GeneralPreferenceFragment(IntPtr javaRef, JniHandleOwnership transfer)
    : base(javaRef, transfer)
{
}

The latter ctor is often needed when the app is coming back from background or when the Java world is invoking the class somehow.

like image 134
Cheesebaron Avatar answered Nov 15 '22 01:11

Cheesebaron