我想在Android设置应用中显示偏好设置屏幕:使用标题,PreferenceActivity,PreferenceFragment和标题类别。
我想把这个结果放在平板电脑上:
这是智能手机上的一个:
如果我只使用基本标题,它会起作用,但是如果我尝试添加类别,它会在智能手机上运行,并在平板电脑上崩溃,在那里我得到异常“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
贝娄是涉及的代码片段。我主要是从Android设置应用来源获得它们。
有什么想法吗?
提前致谢
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));
}
}
}
PreferencesFragment:
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>
最后但并非最不重要的是,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; /* 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;
}
}
答案 0 :(得分:6)
正如bestofbest1所说,问题是Android试图在preferences_headers.xml中显示第一个元素,该元素不包含片段。
为了解决这个问题,我在MainPreferenceActivity的onCreate中添加了以下一行(BEFORE super.onCreate),以便在使用平板电脑时选择默认片段:
if(onIsMultiPane()) getIntent().putExtra(PreferenceActivity.EXTRA_SHOW_FRAGMENT, PreferencesFragment.class.getName());
我还在PreferencesFragment中设置了一个默认片段:
String settings = "DIVE";
if(getArguments() != null) settings = getArguments().getString("settings");
然后是最后一个问题,PreferenceActivity.EXTRA_SHOW_FRAGMENT没有选择左侧的标题。要在MainPreferencesActivity中修复它,请保存对标题的引用(在onBuildHeaders中),并添加:
@Override
protected void onResume() {
// Call super :
super.onResume();
// Select the displayed fragment in the headers (when using a tablet) :
// This should be done by Android, it is a bug fix
if(_headers != null) {
final String displayedFragment = getIntent().getStringExtra(EXTRA_SHOW_FRAGMENT);
if (displayedFragment != null) {
for (final Header header : _headers) {
if (displayedFragment.equals(header.fragment)) {
switchToHeader(header);
break;
}
}
}
}
}
答案 1 :(得分:2)
我遇到了让蒂姆的解决方案为我工作的问题(程序仍会崩溃)。我通过默认选择第一个非类别标题而不是列表中的第一个来以不同的方式解决这个问题。为此,我在onGetInitialHeader
PreferenceActivity
方法
@Override
public Header onGetInitialHeader() {
for (int i = 0; i < mHeaders.size(); i++) {
Header h = mHeaders.get(i);
if (!isCategory(h)) {
return h;
}
}
}
protected static boolean isCategory(Header h) {
return h.fragment == null;
}
mHeaders
只是对onBuildHeaders
调用中保存的标题列表的引用。还应该指出的是,这只是4.3之前的一个问题,因此已经修复。希望这可以帮助别人
答案 2 :(得分:1)
也许第一个标题是默认选择的菜单。如果是这样,它应该有fragment属性来显示它的右侧。
答案 3 :(得分:1)
作为Tim Autin解决方案的一种简单形式,完全禁用多窗格以在平板电脑上生成单窗格,类似手机的显示。
Sleep