Android:PreferenceFragment 与自定义 Preference 生命周期不一致?
Android: PreferenceFragment with custom Preference lifecycle inconsistency?
我正在尝试创建自定义 Preference to be shown in PreferenceFragment as described here: Building a Custom Preference. My custom Preference should look and function as SwitchPreference,但还有一个额外的 TextView
用于错误报告。
我实现了所有功能并且 UI 看起来不错,但是当我的 PreferenceFragment 显示时我无法初始化此 Preference!
Preference.onBindView()
的文档指出:
This is a good place to grab references to custom Views in the layout
and set properties on them.
所以我做到了:
@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();
}
但是,当我在 PreferenceFragment.onResume()
中调用 CustomSwitchPreference.setError(String)
时,我得到了 NPE,因为 txtError
为空。
我试图找到一些解决方法,但看起来 PreferenceFragment 中没有生命周期方法,保证在所有底层 Preferences
初始化其 Views
后调用(我检查了两个Preference.onBindView(View)
和 Preference.onCreateView(ViewGroup)
).
这种行为没有任何意义 - 当显示 PreferenceFragment
时,应该有一些方法可以初始化基础 Preferences
的 UI。我怎样才能做到这一点?
注意:在 CustomPreferenceFragment.onResume()
中调用 customPreference.setTitle(String)
和 customPreference.setSummary(String()
工作正常。这只是额外的 TextView
,我无法获取对...
的引用
CustomSwitchPreference.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();
}
}
CustomPreferenceFragment.java:
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");
}
}
custom_switch_preference_layout.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>
application_settings.xml:
<?xml version="1.0" encoding="utf-8"?>
<PreferenceScreen xmlns:android="http://schemas.android.com/apk/res/android">
<com.example.settings.CustomSwitchPreference
android:key="CUSTOM_PREF"/>
</PreferenceScreen>
我找不到适合这个问题的解决方案 - 这种不一致感觉就像是 AOSP 中的生命周期错误,但我对此不是 100% 确定。
作为变通方法,我定义了一个回调接口,CustomSwitchPreference
在 onBindView
方法中调用它,以通知包含的 PreferenceFragment
它已被初始化:
@Override
protected void onBindView(View view) {
super.onBindView(view);
txtError = (TextView) view.findViewById(R.id.error);
initializationListener.onInitialized(CustomSwitchPreference.this);
}
我想在 onResume
中执行的 CustomSwitchPreference
上的所有操作现在都在 onInitialized
回调中执行。这是一个丑陋的解决方法,需要大量的样板文件,但它似乎有效。
我正在尝试创建自定义 Preference to be shown in PreferenceFragment as described here: Building a Custom Preference. My custom Preference should look and function as SwitchPreference,但还有一个额外的 TextView
用于错误报告。
我实现了所有功能并且 UI 看起来不错,但是当我的 PreferenceFragment 显示时我无法初始化此 Preference!
Preference.onBindView()
的文档指出:
This is a good place to grab references to custom Views in the layout and set properties on them.
所以我做到了:
@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();
}
但是,当我在 PreferenceFragment.onResume()
中调用 CustomSwitchPreference.setError(String)
时,我得到了 NPE,因为 txtError
为空。
我试图找到一些解决方法,但看起来 PreferenceFragment 中没有生命周期方法,保证在所有底层 Preferences
初始化其 Views
后调用(我检查了两个Preference.onBindView(View)
和 Preference.onCreateView(ViewGroup)
).
这种行为没有任何意义 - 当显示 PreferenceFragment
时,应该有一些方法可以初始化基础 Preferences
的 UI。我怎样才能做到这一点?
注意:在 CustomPreferenceFragment.onResume()
中调用 customPreference.setTitle(String)
和 customPreference.setSummary(String()
工作正常。这只是额外的 TextView
,我无法获取对...
CustomSwitchPreference.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();
}
}
CustomPreferenceFragment.java:
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");
}
}
custom_switch_preference_layout.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>
application_settings.xml:
<?xml version="1.0" encoding="utf-8"?>
<PreferenceScreen xmlns:android="http://schemas.android.com/apk/res/android">
<com.example.settings.CustomSwitchPreference
android:key="CUSTOM_PREF"/>
</PreferenceScreen>
我找不到适合这个问题的解决方案 - 这种不一致感觉就像是 AOSP 中的生命周期错误,但我对此不是 100% 确定。
作为变通方法,我定义了一个回调接口,CustomSwitchPreference
在 onBindView
方法中调用它,以通知包含的 PreferenceFragment
它已被初始化:
@Override
protected void onBindView(View view) {
super.onBindView(view);
txtError = (TextView) view.findViewById(R.id.error);
initializationListener.onInitialized(CustomSwitchPreference.this);
}
我想在 onResume
中执行的 CustomSwitchPreference
上的所有操作现在都在 onInitialized
回调中执行。这是一个丑陋的解决方法,需要大量的样板文件,但它似乎有效。