Android:具有自定义首选项生命周期不一致的PreferenceFragment?

时间:2015-11-15 18:04:35

标签: android android-fragments android-preferences

我尝试创建一个自定义Preference,以便在PreferenceFragment中显示,如下所述:Building a Custom Preference。我的自定义首选项应该看起来像SwitchPreference,但是还有一个TextView用于错误报告。

我实现了所有内容并且UI看起来很好,但是当我显示PreferenceFragment时,我无法初始化此Preference!

Preference.onBindView()的文档声明:

  

这是在布局中获取对自定义视图的引用的好地方   并设置它们的属性。

所以我做了:

@Override
protected void onBindView(View view) {
    super.onBindView(view);
    txtError = (TextView) view.findViewById(R.id.error);
}

public void setError(String errorMessage) {
    txtError.setText(errorMessage);
    notifyChanged();
}

但是,当我在CustomSwitchPreference.setError(String)中拨打PreferenceFragment.onResume()时,我会获得NPE,因为txtError为空。

我试图找到一些解决方法,但看起来PreferenceFragment中没有生命周期方法,保证在所有基础Preferences初始化Views之后调用它(我检查了两个{{ 1}}和Preference.onBindView(View))。

这种行为没有任何意义 - 当显示Preference.onCreateView(ViewGroup)时,应该有一些方法来初始化基础Preferences的UI。我怎样才能做到这一点?

注意:PreferenceFragment中对customPreference.setTitle(String)customPreference.setSummary(String()的来电可以正常工作。这只是额外的CustomPreferenceFragment.onResume(),我无法获取对...的引用。

CustomSwitchPreference.java:

TextView

CustomPreferenceFragment.java:

public class CustomSwitchPreference extends SwitchPreference {

    private TextView txtError;

    public CustomSwitchPreference(Context context, AttributeSet attrs, int defStyleAttr, int defStyleRes) {
        super(context, attrs, defStyleAttr, defStyleRes);
    }

    public CustomSwitchPreference(Context context, AttributeSet attrs, int defStyleAttr) {
        super(context, attrs, defStyleAttr);
    }

    public CustomSwitchPreference(Context context, AttributeSet attrs) {
        super(context, attrs);
    }

    public CustomSwitchPreference(Context context) {
        super(context);
    }

    @Override
    protected View onCreateView(ViewGroup parent) {
        setLayoutResource(R.layout.custom_switch_preference_layout);
        return super.onCreateView(parent);
    }

    @Override
    protected void onBindView(View view) {
        super.onBindView(view);
        txtError = (TextView) view.findViewById(R.id.error);
    }

    public void setError(String errorMessage) {
        txtError.setText(errorMessage);
        notifyChanged();
    }

}

custom_switch_preference_layout.xml:

public class CustomPreferenceFragment extends PreferenceFragment {

    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        getPreferenceManager().setSharedPreferencesName(PREFERENCES_FILE_NAME);
        addPreferencesFromResource(R.xml.application_settings);
    }


    @Override
    public void onResume() {
        super.onResume();
        Preference preference = findPreference("CUSTOM_PREF");
        if (preference == null ||
                !CustomSwitchPreference.class.isAssignableFrom(preference.getClass()))
            throw new RuntimeException("couldn't get a valid reference to custom preference");

        CustomSwitchPreference customPreference = (CustomSwitchPreference) preference;
        customPreference.setError("error");
    }
}

application_settings.xml:

<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout
    xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="match_parent">

    <LinearLayout
        android:orientation="vertical"
        android:layout_width="wrap_content"
        android:layout_height="match_parent"
        android:layout_centerVertical="true"
        android:layout_alignParentStart="true"
        android:layout_toStartOf="@android:id/widget_frame">

        <TextView
            android:id="@android:id/title"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:lines="1"/>

        <TextView
            android:id="@android:id/summary"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:maxLines="3"/>

        <TextView
            android:id="@+id/error"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:maxLines="3"/>

    </LinearLayout>

    <FrameLayout
        android:id="@android:id/widget_frame"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_centerVertical="true"
        android:layout_alignParentEnd="true"/>

</RelativeLayout>

1 个答案:

答案 0 :(得分:2)

我找不到适合这个问题的解决方案 - 这种不一致感觉就像是AOSP中的生命周期错误,但我对此并不是百分之百确定。

作为一种解决方法,我定义了一个CustomSwitchPreferenceonBindView方法中调用的回调接口,以通知包含PreferenceFragment的已初始化:

@Override
protected void onBindView(View view) {
    super.onBindView(view);
    txtError = (TextView) view.findViewById(R.id.error);
    initializationListener.onInitialized(CustomSwitchPreference.this);
}

我想在CustomSwitchPreference中执行的onResume上的所有操作现在都在onInitialized回调中执行。这是一个丑陋的解决方法,需要大量的样板,但似乎有效。