我正在编写一个自定义的Android偏好设置屏幕,当标题没有片段时,它会崩溃b / c它期待一个片段 - 我只想要一个标题,作为给定集合的标题部分。尝试搜索,但无济于事,如果这是一个重复,那就很抱歉。
pref_headers.xml
<preference-headers xmlns:android="http://schemas.android.com/apk/res/android">
<header android:id="@+id/headerStaffGeneral" android:title="@string/staff_general" /> <!-- This causes a crash as name == null -->
<header
android:id="@+id/headerSettings"
android:fragment="com.example.ex.prefs.SettingsPreferencesFragment"
android:title="@string/staff_manager_settings"
android:icon="@drawable/ic_action_settings"
/>
</preference-headers>
如果需要包含任何其他代码,我可以将其包含在内,但问题的本质是我是否应该将崩溃的HEADER
标记替换为其他内容。
更新:
LogCat Output
FATAL EXCEPTION: main
java.lang.RuntimeException: Unable to start activity ComponentInfo{com.example.ex/com.example.ex.prefs.PrefsActivity}: java.lang.NullPointerException: name == null
at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:2245)
at android.app.ActivityThread.handleLaunchActivity(ActivityThread.java:2295)
at android.app.ActivityThread.access$700(ActivityThread.java:150)
at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1280)
at android.os.Handler.dispatchMessage(Handler.java:99)
at android.os.Looper.loop(Looper.java:175)
at android.app.ActivityThread.main(ActivityThread.java:5279)
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:1102)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:869)
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:582)
at android.preference.PreferenceActivity.switchToHeaderInner(PreferenceActivity.java:1245)
at android.preference.PreferenceActivity.switchToHeader(PreferenceActivity.java:1278)
at android.preference.PreferenceActivity.onCreate(PreferenceActivity.java:647)
at android.app.Activity.performCreate(Activity.java:5283)
at android.app.Instrumentation.callActivityOnCreate(Instrumentation.java:1097)
at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:2209)
... 11 more
PrefsActivity.java
package com.example.ex.prefs;
import java.util.ArrayList;
import java.util.List;
import android.preference.PreferenceActivity;
import android.widget.ListAdapter;
import com.example.ex.R;
public class PrefsActivity extends PreferenceActivity {
private List<Header> mHeaders;
protected void onResume() {
super.onResume();
setTitle(R.string.staff_manager_settings);
if (getListAdapter() instanceof PrefsHeaderAdapter)
((PrefsHeaderAdapter) getListAdapter()).resume();
}
protected void onPause() {
super.onPause();
if (getListAdapter() instanceof PrefsHeaderAdapter)
((PrefsHeaderAdapter) getListAdapter()).pause();
}
public void onBuildHeaders(List<Header> target) {
// Called when the settings screen is up for the first time
// we load the headers from our xml description
loadHeadersFromResource(R.xml.pref_headers, target);
mHeaders = target;
}
public void setListAdapter(ListAdapter adapter) {
int i, count;
if (mHeaders == null) {
mHeaders = new ArrayList<Header>();
// When the saved state provides the list of headers,
// onBuildHeaders is not called
// so we build it from the adapter given, then use our own adapter
count = adapter.getCount();
for (i = 0; i < count; ++i)
mHeaders.add((Header) adapter.getItem(i));
}
super.setListAdapter(new PrefsHeaderAdapter(this, mHeaders));
}
}
如果从HEADER
文件中删除了第一个pref_headers.xml
标记,则不会显示错误。
答案 0 :(得分:1)
你应该有所作为,但也许你需要一个android:id
值。如果您查看“设置”应用的首选项标题,则会看到以下内容:
<preference-headers
xmlns:android="http://schemas.android.com/apk/res/android">
<!-- WIRELESS and NETWORKS -->
<header android:id="@+id/wireless_section"
android:title="@string/header_category_wireless_networks" />
<!-- Wifi -->
<header
android:id="@+id/wifi_settings"
android:fragment="com.android.settings.wifi.WifiSettings"
android:title="@string/wifi_settings_title"
android:icon="@drawable/ic_settings_wireless" />
...
因此,他们似乎在标题列表中的部分标题中使用了<header>
而没有android:fragment
。
答案 1 :(得分:1)
首选项标头的XML是正确的,不需要android:id
属性(但永远不会受伤)。我需要添加两件事:setListAdapter
和onGetInitialHeader
。
以下是所有3个文件的最终代码:
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;
}
}
}
关键是重写onGetInitialHeader以确保它不是第一个标题b / c根据Android - Headers categories in PreferenceActivity with PreferenceFragment的信息,Android默认加载第一个是我的类别标题并假设它是一个片段但是,既然不是,它就崩溃了。此ListAdapter用于管理列表的特征并确定标题类型 - 这是可靠地确定标题类型所必需的,无需对答案进行硬编码。
我希望这可以帮助别人,因为我已经花了好几天了!