Xamarin.Android偏好设置页面跳转失败:Fragment实例化异常
Xamarin Android 偏好设置页面跳转实例化异常问题
问题概述
- 简述:无法实现偏好设置页面跳转,运行时抛出
AndroidX.Fragment.App.Fragment.InstantiationException异常 - 场景:基于Xamarin/Android的应用,使用AndroidX.Preference实现单页面偏好设置后,尝试将高级设置拆分至单独页面
- 核心错误:点击跳转项时,系统提示无法实例化目标Fragment类,但该类实际存在
示例代码
PreferencesActivity
namespace App1 { [Android.App.Activity(Label = "PreferencesActivity")] public class PreferencesActivity : AndroidX.AppCompat.App.AppCompatActivity { protected override void OnCreate(Android.OS.Bundle savedInstanceState) { base.OnCreate(savedInstanceState); SetContentView(Resource.Layout.preferences_activity); SupportFragmentManager.BeginTransaction().Replace(Resource.Id.preferences_fragment_container, new RootPreferencesFragment()).Commit(); } } }
preference_activity.xml
<?xml version="1.0" encoding="utf-8"?> <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" xmlns:app="http://schemas.android.com/apk/res-auto" android:layout_width="match_parent" android:layout_height="wrap_content" android:orientation="vertical"> <androidx.fragment.app.FragmentContainerView android:id="@+id/preferences_fragment_container" android:layout_width="match_parent" android:layout_height="wrap_content"/> </LinearLayout>
RootPreferencesFragment
namespace App1 { public class RootPreferencesFragment : AndroidX.Preference.PreferenceFragmentCompat { public override void OnCreate(Android.OS.Bundle savedInstanceState) { base.OnCreate(savedInstanceState); } public override void OnCreatePreferences(Android.OS.Bundle savedInstanceState, string rootKey) { SetPreferencesFromResource(Resource.Xml.preferences_root, rootKey); } } }
preferences_root.xml
<?xml version="1.0" encoding="utf-8"?> <androidx.preference.PreferenceScreen xmlns:android="http://schemas.android.com/apk/res/android" xmlns:app="http://schemas.android.com/apk/res-auto"> <androidx.preference.SwitchPreference android:key="pref1" android:title="Prefercence 1"/> <androidx.preference.Preference android:title="Advanced" app:fragment="com.companyname.app1.AdvancedPreferencesFragment"/> </androidx.preference.PreferenceScreen>
AdvancedPreferencesFragment
namespace App1 { public class AdvancedPreferencesFragment : AndroidX.Preference.PreferenceFragmentCompat { public override void OnCreate(Android.OS.Bundle savedInstanceState) { base.OnCreate(savedInstanceState); } public override void OnCreatePreferences(Android.OS.Bundle savedInstanceState, string rootKey) { SetPreferencesFromResource(Resource.Xml.preferences_advanced, rootKey); } } }
preferences_advanced.xml
<?xml version="1.0" encoding="utf-8"?> <androidx.preference.PreferenceScreen xmlns:android="http://schemas.android.com/apk/res/android" xmlns:app="http://schemas.android.com/apk/res-auto"> <androidx.preference.SwitchPreference android:key="pref2" android:title="Advanced Prefercence 2"/> </androidx.preference.PreferenceScreen>
已尝试方案
- 调整
app:fragment属性值,尝试过com.companyname.App1.AdvancedPreferencesFragment、App1.AdvancedPreferencesFragment等多种类名组合,均无效 - 为Fragment添加空默认构造函数,无效果
- 实现
IOnPreferenceStartFragmentCallback接口,但FragmentFactory.Instantiate()仍抛出相同异常
解决方案
原因分析
Xamarin编译C#代码时,会自动为C#类生成带后缀的Java包装类(比如AdvancedPreferencesFragment会变为AdvancedPreferencesFragment_),直接在XML中指定C#类名无法被Android系统识别。
解决步骤
方案一:手动实例化Fragment(推荐)
- 修改
PreferencesActivity,实现IOnPreferenceStartFragmentCallback接口,手动创建目标Fragment实例:
namespace App1 { [Android.App.Activity(Label = "PreferencesActivity")] public class PreferencesActivity : AndroidX.AppCompat.App.AppCompatActivity, AndroidX.Preference.PreferenceFragmentCompat.IOnPreferenceStartFragmentCallback { protected override void OnCreate(Android.OS.Bundle savedInstanceState) { base.OnCreate(savedInstanceState); SetContentView(Resource.Layout.preferences_activity); SupportFragmentManager.BeginTransaction().Replace(Resource.Id.preferences_fragment_container, new RootPreferencesFragment()).Commit(); } bool AndroidX.Preference.PreferenceFragmentCompat.IOnPreferenceStartFragmentCallback.OnPreferenceStartFragment(AndroidX.Preference.PreferenceFragmentCompat caller, AndroidX.Preference.Preference pref) { // 通过key判断跳转目标,比标题更可靠 AndroidX.Preference.PreferenceFragmentCompat fragment = pref.Key == "advanced_pref" ? new AdvancedPreferencesFragment() : null; if (fragment == null) return false; // 传递参数并设置目标Fragment fragment.Arguments = pref.Extras; fragment.SetTargetFragment(caller, 0); // 替换Fragment并加入回退栈 SupportFragmentManager.BeginTransaction() .Replace(Resource.Id.preferences_fragment_container, fragment) .AddToBackStack(null) .Commit(); return true; } } }
- 修改
preferences_root.xml,移除app:fragment属性,添加唯一key标识跳转项:
<?xml version="1.0" encoding="utf-8"?> <androidx.preference.PreferenceScreen xmlns:android="http://schemas.android.com/apk/res/android" xmlns:app="http://schemas.android.com/apk/res-auto"> <androidx.preference.SwitchPreference android:key="pref1" android:title="Prefercence 1"/> <androidx.preference.Preference android:key="advanced_pref" android:title="Advanced"/> </androidx.preference.PreferenceScreen>
方案二:通过[Register]特性指定Java类名
如果希望保留XML中的app:fragment属性,可为Fragment添加[Register]特性固定Java类名:
namespace App1 { [Register("com.companyname.app1.AdvancedPreferencesFragment")] public class AdvancedPreferencesFragment : AndroidX.Preference.PreferenceFragmentCompat { // 必须保留空默认构造函数 public AdvancedPreferencesFragment() { } public override void OnCreate(Android.OS.Bundle savedInstanceState) { base.OnCreate(savedInstanceState); } public override void OnCreatePreferences(Android.OS.Bundle savedInstanceState, string rootKey) { SetPreferencesFromResource(Resource.Xml.preferences_advanced, rootKey); } } }
此时XML中的app:fragment属性值可直接写com.companyname.app1.AdvancedPreferencesFragment,同时需确保PreferencesActivity实现IOnPreferenceStartFragmentCallback接口触发跳转。
内容的提问来源于stack exchange,提问作者Andy Johnson
相关产品推荐
相关产品推荐

