I would like to display a preferences screen similar to that in the Android settings app: using headers, PreferenceActivity, PreferenceFragment categories and headers.
I do not get this result on the tablet:

And this is on the smartphone:

It works if I just use the main headers, but if I try to add categories, it works on the smartphone and crashes to the tablet, where I get the exception "java.lang.NullPointerException: name == null"
FATAL EXCEPTION: main java.lang.RuntimeException: Unable to start activity ComponentInfo{fr.ifremer.testandroid/fr.ifremer.testandroid.models.preferences.MainPreferenceActivity}: java.lang.NullPointerException: name == null at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:2110) at android.app.ActivityThread.handleLaunchActivity(ActivityThread.java:2135) at android.app.ActivityThread.access$700(ActivityThread.java:140) at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1237) at android.os.Handler.dispatchMessage(Handler.java:99) at android.os.Looper.loop(Looper.java:137) at android.app.ActivityThread.main(ActivityThread.java:4921) at java.lang.reflect.Method.invokeNative(Native Method) at java.lang.reflect.Method.invoke(Method.java:511) at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:1038) at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:805) at dalvik.system.NativeStart.main(Native Method) Caused by: java.lang.NullPointerException: name == null at java.lang.VMClassLoader.findLoadedClass(Native Method) at java.lang.ClassLoader.findLoadedClass(ClassLoader.java:354) at java.lang.ClassLoader.loadClass(ClassLoader.java:491) at java.lang.ClassLoader.loadClass(ClassLoader.java:461) at android.app.Fragment.instantiate(Fragment.java:574) at android.preference.PreferenceActivity.switchToHeaderInner(PreferenceActivity.java:1222) at android.preference.PreferenceActivity.switchToHeader(PreferenceActivity.java:1255) at android.preference.PreferenceActivity.onCreate(PreferenceActivity.java:630) at fr.ifremer.testandroid.models.preferences.MainPreferenceActivity.onCreate(MainPreferenceActivity.java:19) at android.app.Activity.performCreate(Activity.java:5206) at android.app.Instrumentation.callActivityOnCreate(Instrumentation.java:1094) at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:2074) ... 11 more
The following are parts of the code. I got them mainly from the source of the Android settings application.
Any idea?
Thank you in advance
MainPreferenceActivity:
public class MainPreferenceActivity extends PreferenceActivity { private static List<Header> _headers; @Override public void onBuildHeaders(List<Header> headers) { _headers = headers; loadHeadersFromResource(R.xml.preference_headers, headers); } @Override public void setListAdapter(ListAdapter adapter) { if (adapter == null) { super.setListAdapter(null); } else { super.setListAdapter(new HeaderAdapter(this, _headers)); } } }
Preferences
public class PreferencesFragment extends PreferenceFragment { @Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); String settings = getArguments().getString("settings"); if (settings.equals("DIVE")) { addPreferencesFromResource(R.xml.preference_dive_tile); } else if (settings.equals("MAP")) { addPreferencesFromResource(R.xml.preference_map_tile); } } }
preference_headers.xml:
<?xml version="1.0" encoding="utf-8"?> <preference-headers xmlns:android="http://schemas.android.com/apk/res/android" > <header android:id="@+id/header_section_1" android:title="Section 1" /> <header android:fragment="fr.ifremer.testandroid.models.preferences.PreferencesFragment" android:summary="DIVE summary" android:title="DIVE title" > <extra android:name="settings" android:value="DIVE" /> </header> <header android:fragment="fr.ifremer.testandroid.models.preferences.PreferencesFragment" android:summary="MAP summary" android:title="MAP title" > <extra android:name="settings" android:value="MAP" /> </header> </preference-headers>
And last but not least: HeaderAdapter:
public class HeaderAdapter extends ArrayAdapter<Header> { static final int HEADER_TYPE_CATEGORY = 0; static final int HEADER_TYPE_NORMAL = 1; private static final int HEADER_TYPE_COUNT = HEADER_TYPE_NORMAL + 1; private LayoutInflater mInflater; private static class HeaderViewHolder { ImageView icon; TextView title; TextView summary; } public HeaderAdapter(Context context, List<Header> objects) { super(context, 0, objects); mInflater = (LayoutInflater) context.getSystemService(Context.LAYOUT_INFLATER_SERVICE); } static int getHeaderType(Header header) { if (header.fragment == null && header.intent == null) return HEADER_TYPE_CATEGORY; else return HEADER_TYPE_NORMAL; } @Override public int getItemViewType(int position) { Header header = getItem(position); return getHeaderType(header); } @Override public boolean areAllItemsEnabled() { return false; } @Override public boolean isEnabled(int position) { return getItemViewType(position) != HEADER_TYPE_CATEGORY; } @Override public int getViewTypeCount() { return HEADER_TYPE_COUNT; } @Override public boolean hasStableIds() { return true; } @Override public View getView(int position, View convertView, ViewGroup parent) { HeaderViewHolder holder; Header header = getItem(position); int headerType = getHeaderType(header); View view = null; if (convertView == null) { holder = new HeaderViewHolder(); switch (headerType) { case HEADER_TYPE_CATEGORY: view = new TextView(getContext(), null, android.R.attr.listSeparatorTextViewStyle); holder.title = (TextView) view; break; case HEADER_TYPE_NORMAL: view = mInflater.inflate(R.layout.preference_header_item, parent, false); holder.icon = (ImageView) view.findViewById(R.id.icon); holder.title = (TextView) view.findViewById(R.id.title); holder.summary = (TextView) view.findViewById(R.id.summary); break; } view.setTag(holder); } else { view = convertView; holder = (HeaderViewHolder) view.getTag(); }