Android中PreferenceFragment监听事件致空指针崩溃问题求助
问题原因分析
你遇到的崩溃问题,核心原因是FragmentTransaction的commit()方法是异步执行的——当你调用commit()后,系统并不会立刻完成Fragment的创建和挂载,而是把这个操作放到主线程的消息队列里等待执行。这时候你紧接着调用getFragmentManager().findFragmentByTag("fragTag"),得到的custFragment必然是null,后续用这个null对象调用findPreference()自然会触发空指针异常。
修复方案
这里提供两种靠谱的修复思路,你可以根据需求选择:
方案一:将监听逻辑移到SettingsFragment内部(推荐)
把Preference的点击监听逻辑放到SettingsFragment里,这样既符合Fragment的职责划分,也能避免Fragment未初始化完成就调用方法的问题。修改后的代码如下:
修改后的SettingsFragment.java
package com.triunedev.foodeze; import android.os.Bundle; import android.preference.CheckBoxPreference; import android.preference.EditTextPreference; import android.preference.Preference; import android.preference.PreferenceFragment; public class SettingsFragment extends PreferenceFragment { public SettingsFragment() { // Required empty public constructor } @Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); // Load the preferences from an XML resource addPreferencesFromResource(R.xml.preferences); // 在这里获取Preference实例并设置监听 EditTextPreference textPref = (EditTextPreference) findPreference("KEYWORD"); CheckBoxPreference checkPref = (CheckBoxPreference) findPreference("SHOWMENU"); textPref.setOnPreferenceClickListener(new Preference.OnPreferenceClickListener() { public boolean onPreferenceClick(Preference preference) { checkPref.setChecked(false); return false; } }); } }
修改后的SettingsActivity.java
package com.triunedev.foodeze; import android.app.Activity; import android.os.Bundle; public class SettingsActivity extends Activity { @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); // Display the fragment as the main content. getFragmentManager().beginTransaction() .replace(android.R.id.content, new SettingsFragment(), "fragTag") .commit(); // 这里不再需要获取Fragment实例和设置监听,逻辑都移到Fragment里了 } }
方案二:强制立刻执行Fragment事务
如果你坚持要在Activity里处理监听,可以在commit()之后调用executePendingTransactions(),让系统立刻执行Fragment的创建和挂载操作,这样后续的findFragmentByTag就能拿到有效的Fragment实例:
修改后的SettingsActivity.java关键代码
@Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); // Display the fragment as the main content. getFragmentManager().beginTransaction() .replace(android.R.id.content, new SettingsFragment(), "fragTag") .commit(); // 强制立刻执行所有待处理的Fragment事务 getFragmentManager().executePendingTransactions(); custFragment = (SettingsFragment) getFragmentManager().findFragmentByTag("fragTag"); textPref = (EditTextPreference) custFragment.findPreference("KEYWORD"); checkPref = (CheckBoxPreference) custFragment.findPreference("SHOWMENU"); textPref.setOnPreferenceClickListener(new Preference.OnPreferenceClickListener() { public boolean onPreferenceClick(Preference preference) { checkPref.setChecked(false); return false; } }); }
额外提示
方案一更推荐,因为Preference相关的逻辑本来就属于SettingsFragment的职责范围,把逻辑内聚在Fragment里,代码结构更清晰,也能避免类似的生命周期相关问题。
内容的提问来源于stack exchange,提问作者F. Moss
相关产品推荐
相关产品推荐

