Note that there are some explanatory texts on larger screens.

plurals
  1. POAndroid - Headers categories in PreferenceActivity with PreferenceFragment
    primarykey
    data
    text
    <p>I would like to display a preference screen like the one in the Android settings app : using headers, PreferenceActivity, PreferenceFragment and headers categories.</p> <p>I wan't this result on a tablet :</p> <p><img src="https://i.stack.imgur.com/0XkKw.png" alt="enter image description here"></p> <p>And this one on a smartphone :</p> <p><img src="https://i.stack.imgur.com/LdLuM.png" alt="enter image description here"></p> <p>It works if I just use the basic headers, but if I try to add categories, it works on the smartphone, and crash on the tablet, where I get the exception "java.lang.NullPointerException: name == null" :</p> <pre><code>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 </code></pre> <p>Bellow are the pieces of code involved. I got them mostly from the Android settings app source.</p> <p>Any idea ?</p> <p>Thanks in advance</p> <hr> <p>MainPreferenceActivity :</p> <pre><code>public class MainPreferenceActivity extends PreferenceActivity { private static List&lt;Header&gt; _headers; @Override public void onBuildHeaders(List&lt;Header&gt; 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)); } } } </code></pre> <p>PreferencesFragment :</p> <pre><code>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); } } } </code></pre> <p>preference_headers.xml :</p> <pre><code>&lt;?xml version="1.0" encoding="utf-8"?&gt; &lt;preference-headers xmlns:android="http://schemas.android.com/apk/res/android" &gt; &lt;header android:id="@+id/header_section_1" android:title="Section 1" /&gt; &lt;header android:fragment="fr.ifremer.testandroid.models.preferences.PreferencesFragment" android:summary="DIVE summary" android:title="DIVE title" &gt; &lt;extra android:name="settings" android:value="DIVE" /&gt; &lt;/header&gt; &lt;header android:fragment="fr.ifremer.testandroid.models.preferences.PreferencesFragment" android:summary="MAP summary" android:title="MAP title" &gt; &lt;extra android:name="settings" android:value="MAP" /&gt; &lt;/header&gt; &lt;/preference-headers&gt; </code></pre> <p>Last but not least, HeaderAdapter :</p> <pre><code>public class HeaderAdapter extends ArrayAdapter&lt;Header&gt; { 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&lt;Header&gt; objects) { super(context, 0, objects); mInflater = (LayoutInflater) context.getSystemService(Context.LAYOUT_INFLATER_SERVICE); } static int getHeaderType(Header header) { if (header.fragment == null &amp;&amp; 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; /* because of categories */ } @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(); } // All view fields must be updated every time, because the view may be recycled switch (headerType) { case HEADER_TYPE_CATEGORY : holder.title.setText(header.getTitle(getContext().getResources())); break; case HEADER_TYPE_NORMAL : holder.icon.setImageResource(header.iconRes); holder.title.setText(header.getTitle(getContext().getResources())); CharSequence summary = header.getSummary(getContext().getResources()); if (!TextUtils.isEmpty(summary)) { holder.summary.setVisibility(View.VISIBLE); holder.summary.setText(summary); } else { holder.summary.setVisibility(View.GONE); } break; } return view; } } </code></pre>
    singulars
    1. This table or related slice is empty.
    plurals
    1. This table or related slice is empty.
    1. This table or related slice is empty.
    1. This table or related slice is empty.
    1. This table or related slice is empty.
 

Querying!

 
Guidance

SQuiL has stopped working due to an internal error.

If you are curious you may find further information in the browser console, which is accessible through the devtools (F12).

Reload