2013-03-21 6 views
6

Android設定アプリのような設定画面を表示したいと思います。ヘッダー、PreferenceActivity、PreferenceFragment、ヘッダーのカテゴリを使用しています。Android - PreferenceActivityのヘッダーカテゴリPreferenceActivity with PreferenceFragment

enter image description here

そしてこのスマートフォン上の1:

私はタブレット上でこの結果をwan't私は基本的なヘッダを使用する場合

enter image description here

それは動作しますが、カテゴリを追加しようとすると、スマートフォンで動作し、タブレット上でクラッシュし、「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; 
    } 
} 

答えて

1

たぶん、最初のヘッダーのデフォルト選択したメニューです。もしそうなら、それは右にそれを示すフラグメント属性を持っているはずです。

+0

申し訳ありませんが、私はこの問題をしばらく断念しました。そうです、最初のヘッダーがフラグメントであると考えられたので動作しませんでした。 しかし、それを修正するために、最初のヘッダにフラグメントを追加しませんでした。 –

6

bestofbest1が言ったように、問題は、Androidがpreferences_headers.xmlにフラグメントを含まない最初の要素を表示しようとしたことでした。それを修正する

が、私はタブレットを使用する場合、デフォルトのフラグメントを選択するためにMainPreferenceActivityののonCreateで(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; 
       } 
      } 
     } 
    } 
} 
2

私は(プログラムがまだクラッシュ)問題は私のために働くためにティムのソリューションを取得しました。私はこれを別の方法で、リストの最初のものではなく最初の非カテゴリのヘッダーをデフォルトで選択するだけで済ませました。これを行うには、私は私の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方法onGetInitialHeaderをオーバーライドはonBuildHeadersへの呼び出しで保存されたヘッダリストにちょうど参照です。これは、4.3以前の問題に過ぎないことにも注意してください。これは修正されています。これが誰かを助けることを望む

1

もっと簡単なTim Autinの解決策として、複数のペインを完全に無効にして、タブレットに電話のような単一のペインを表示させます。

public class PreferencesActivity extends PreferenceActivity { 

    @Override 
    protected void onCreate(Bundle savedInstanceState) { 
     if(onIsMultiPane()) 
      getIntent().putExtra(PreferenceActivity.EXTRA_NO_HEADERS, true); 
     super.onCreate(savedInstanceState); 
    } 
... 
} 
+0

私の好みの断片はAndroid 4と5で動作しましたが、Android 6を使用しているときはシングルペインモードになっていました。これはすべてを複数のペインに戻す唯一のソリューションでした。ありがとう!!! – Logic1

関連する問題