The XML for the preference headers was correct and did not need an android:id
attribute (though, never hurts). I needed to add 2 things: setListAdapter
and onGetInitialHeader
.
Here is the final code for all 3 files:
prefs_headers.xml
<?xml version="1.0" encoding="utf-8"?>
<preference-headers xmlns:android="http://schemas.android.com/apk/res/android">
<header android:title="@string/staff_general"/>
<header
android:id="@+id/headerSettings"
android:fragment="com.example.ex.prefs.SettingsPreferencesFragment"
android:icon="@drawable/ic_action_settings"
android:title="@string/staff_manager_settings"/>
<header
android:id="@+id/headerHistory"
android:fragment="com.example.ex.prefs.HistoryPreferencesFragment"
android:icon="@drawable/ic_action_event"
android:title="@string/staff_manager_history"/>
<header android:title="@string/staff_special" />
<header
android:id="@+id/headerNetwork"
android:fragment="com.example.ex.prefs.NetworkPreferencesFragment"
android:icon="@drawable/ic_action_cloud"
android:title="@string/staff_manager_network"/>
<header
android:id="@+id/headerPrinter"
android:fragment="com.example.ex.prefs.PrinterPreferencesFragment"
android:icon="@drawable/ic_action_star"
android:title="@string/staff_manager_star_printer"/>
</preference-headers>
PrefsActivity.java
package com.example.ex.prefs;
import java.util.List;
import android.preference.PreferenceActivity;
import android.preference.PreferenceActivity.Header;
import android.util.Log;
import android.widget.ListAdapter;
import com.example.ex.R;
public class PrefsActivity extends PreferenceActivity {
private static List<Header> _headers;
@Override
public void setListAdapter(ListAdapter adapter) {
if (adapter == null) {
super.setListAdapter(null);
} else {
super.setListAdapter(new PrefsHeaderAdapter(this, _headers));
}
}
@Override
public void onBuildHeaders(List<Header> target) {
_headers = target;
loadHeadersFromResource(R.xml.pref_headers, target);
}
@Override
public Header onGetInitialHeader() {
super.onResume();
if (PrefsActivity._headers != null) {
for (int i = 0; i < PrefsActivity._headers.size(); i++) {
Header h = PrefsActivity._headers.get(i);
if (PrefsHeaderAdapter.getHeaderType(h) != PrefsHeaderAdapter.HEADER_TYPE_CATEGORY) {
return h;
}
}
}
return null;
}
}
PrefsHeaderAdapter.java
package com.example.ex.prefs;
import java.util.List;
import android.content.Context;
import android.preference.PreferenceActivity.Header;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.ArrayAdapter;
import android.widget.ImageView;
import android.widget.TextView;
import com.example.ex.R;
public class PrefsHeaderAdapter extends ArrayAdapter<Header> {
static final int HEADER_TYPE_CATEGORY = 0;
static final int HEADER_TYPE_NORMAL = 1;
private LayoutInflater mInflater;
public PrefsHeaderAdapter(Context context, List<Header> objects) {
super(context, 0, objects);
mInflater = (LayoutInflater) context.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
}
public View getView(int position, View convertView, ViewGroup parent) {
Header header = getItem(position);
int headerType = getHeaderType(header);
View view = null;
switch (headerType) {
case HEADER_TYPE_CATEGORY:
view = mInflater.inflate(android.R.layout.preference_category, parent, false);
((TextView) view.findViewById(android.R.id.title)).setText(header.getTitle(getContext().getResources()));
break;
case HEADER_TYPE_NORMAL:
view = mInflater.inflate(R.layout.preference_header_item, parent, false);
((ImageView) view.findViewById(android.R.id.icon)).setImageResource(header.iconRes);
((TextView) view.findViewById(android.R.id.title)).setText(header.getTitle(getContext().getResources()));
((TextView) view.findViewById(android.R.id.summary)).setText(header.getSummary(getContext().getResources()));
break;
}
return view;
}
@Override
public boolean isEnabled(int position) {
return getItemViewType(position) != HEADER_TYPE_CATEGORY;
}
@Override
public boolean areAllItemsEnabled() {
return false;
}
@Override
public int getViewTypeCount() {
return 2;
}
@Override
public boolean hasStableIds() {
return true;
}
public static int getHeaderType(Header header) {
if ((header.fragment == null) && (header.intent == null)) {
return HEADER_TYPE_CATEGORY;
} else {
return HEADER_TYPE_NORMAL;
}
}
}
The key was overriding the onGetInitialHeader to ensure that it wasn't the first header b/c according to the info at Android - Headers categories in PreferenceActivity with PreferenceFragment , Android loads the first by default which was my category header and assumes it is a fragment, but since it isn't, it crashed. This ListAdapter is used to manage the characteristics of the list and determine header types -- necessary to reliably determine the header type w/o hard-coding the answer.
I hope this helps someone else as I've spent days on this!