创建首选项活动后,我注意到尽管选中onSharedPreferenceChanged
,但选中复选框首选项后,我的主活动仍未更改主题。有谁知道哪里出了问题以及如何解决?
styles.xml
<!-- Base application theme. -->
<style name="AppTheme" parent="android:Theme.Material.Light.DarkActionBar">
<!--<item name="android:windowBackground">@color/colorLight</item>-->
</style>
<style name="MyDarkMaterialTheme" parent="android:Theme.Material">
<item name="android:windowBackground">@android:color/black</item>
</style>
<style name="MyLightMaterialTheme" parent="android:Theme.Material.Light.DarkActionBar">
<item name="android:windowBackground">@color/colorLight</item>
</style>
MainActivity类
public class MainActivity extends Activity {
boolean themeState;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setTheme(R.style.MyDarkMaterialTheme);
setContentView(R.layout.activity_main);
}
@Override
public boolean onCreateOptionsMenu(Menu menu) {
getMenuInflater().inflate(R.menu.menu_main, menu);
return true;
}
@Override
public boolean onOptionsItemSelected(MenuItem item) {
switch (item.getItemId()) {
case R.id.action_settings:
Intent settingsIntent = new Intent(this, SettingsActivity.class);
startActivity(settingsIntent);
return true;
default:
return super.onOptionsItemSelected(item);
}
}
@Override
public void onResume(){
super.onResume();
loadPreferences();
displaySettings();
}
private void loadPreferences(){
SharedPreferences sharedPreferences = PreferenceManager.getDefaultSharedPreferences(this);
themeState = sharedPreferences.getBoolean("pref_pref1", true);
}
public void displaySettings() {
if (themeState) {
setTheme(R.style.MyDarkMaterialTheme);
recreate();
} else {
setTheme(R.style.MyLightMaterialTheme);
recreate();
}
}
}
SettingsActivity类
public class SettingsActivity extends Activity {
boolean themeState;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_settings);
if (savedInstanceState == null) {
Fragment preferenceFragment = new SettingsFragment();
FragmentTransaction ft = getFragmentManager().beginTransaction();
ft.add(R.id.pref_container, preferenceFragment);
ft.commit();
}
}
@Override
public boolean onOptionsItemSelected(MenuItem item) {
if (item.getItemId() == android.R.id.home) {
final Intent intent = getParentActivityIntent();
if(intent != null){
intent.addFlags(Intent.FLAG_ACTIVITY_NO_ANIMATION);
}
onBackPressed();
return true;
}
return super.onOptionsItemSelected(item);
}
@Override
public void onResume(){
super.onResume();
loadPreferences();
displaySettings();
}
private void loadPreferences(){
SharedPreferences sharedPreferences = PreferenceManager.getDefaultSharedPreferences(this);
themeState = sharedPreferences.getBoolean("pref_pref1", true);
}
public void displaySettings() {
if (themeState) {
getApplication().setTheme(R.style.MyDarkMaterialTheme);
recreate();
} else {
getApplication().setTheme(R.style.MyLightMaterialTheme);
recreate();
}
}
}
SettingsFragment类
public class SettingsFragment extends PreferenceFragment {
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
//Load the Preferences from the XML file
addPreferencesFromResource(R.xml.app_preferences);
}
@Override
public void onActivityCreated(Bundle savedInstanceState) {
super.onActivityCreated(savedInstanceState);
new SharedPreferences.OnSharedPreferenceChangeListener() {
@Override
public void onSharedPreferenceChanged(SharedPreferences sharedPreferences, String key) {
// Settings activity or fragment should restart with changes applied
}
};
}
}
xml / app_preferences
<?xml version="1.0" encoding="utf-8"?>
<PreferenceScreen
xmlns:android="http://schemas.android.com/apk/res/android">
<CheckBoxPreference
android:key="pref_pref1"
android:title="@string/dark_theme"
android:defaultValue="false"
android:layout="@layout/preference_multiline"
/>
</PreferenceScreen>
Csongi77的建议
public class SettingsFragment extends PreferenceFragment implements Preference.OnPreferenceChangeListener {
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
//Load the Preferences from the XML file
addPreferencesFromResource(R.xml.app_preferences);
// Find appropriate preference
CheckBoxPreference mThemePreference =(CheckBoxPreference)getPreferenceManager().findPreference("pref_pref1");
// we have to set up listener in order for persisting change to new value
mThemePreference.setOnPreferenceChangeListener(this);
SharedPreferences sharedPreferences = PreferenceManager.getDefaultSharedPreferences(mThemePreference.getContext());
Boolean value=sharedPreferences.getBoolean("pref_pref1",true);
onPreferenceChange(mThemePreference, value);
}
// overriding onPreferenceChange - if we return true, the preference will be persisted
@Override
public boolean onPreferenceChange(Preference preference, Object newValue) {
String preferenceKey = preference.getKey();
// we have to check the preference type and key, maybe later we have more preferences....
if(preference instanceof CheckBoxPreference){
if(preferenceKey.equals("pref_pref1")){
((CheckBoxPreference)preference).setChecked((Boolean)newValue);
// ... do other preference related stuff here - if necessary, for example setSummary, etc...
getActivity().setTheme(R.style.MyDarkMaterialTheme);
} else {
getActivity().setTheme(R.style.MyLightMaterialTheme);
}
}
return true;
}
}
Logcat
Process: com.companyname.appname, PID: 4505
java.lang.NullPointerException: Attempt to invoke interface method 'void com.companyname.appname.SettingsFragment$PreferenceXchangeListener.onXchange(java.lang.Boolean)' on a null object reference
at com.companyname.appname.SettingsFragment.onPreferenceChange(SettingsFragment.java:57)
at android.preference.Preference.callChangeListener(Preference.java:928)
at android.preference.TwoStatePreference.onClick(TwoStatePreference.java:64)
at android.preference.Preference.performClick(Preference.java:983)
at android.preference.PreferenceScreen.onItemClick(PreferenceScreen.java:214)
at android.widget.AdapterView.performItemClick(AdapterView.java:300)
at android.widget.AbsListView.performItemClick(AbsListView.java:1143)
at android.widget.AbsListView$PerformClick.run(AbsListView.java:3044)
at android.widget.AbsListView$3.run(AbsListView.java:3833)
at android.os.Handler.handleCallback(Handler.java:739)
at android.os.Handler.dispatchMessage(Handler.java:95)
at android.os.Looper.loop(Looper.java:135)
at android.app.ActivityThread.main(ActivityThread.java:5221)
at java.lang.reflect.Method.invoke(Native Method)
at java.lang.reflect.Method.invoke(Method.java:372)
at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:899)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:694)
SettingsActivity类
public class SettingsActivity extends Activity implements SettingsFragment.PreferenceXchangeListener {
private static final String TAG = SettingsActivity.class.getSimpleName();
// declaring initial value for applying appropriate Theme
private Boolean mCurrentValue;
@Override
protected void onCreate(Bundle savedInstanceState) {
// Checking which Theme should be used. IMPORTANT: applying Themes MUST called BEFORE super.onCreate() and setContentView!!!
Log.d(TAG, "onCreate:::: retrieving preferences");
SharedPreferences mSharedPreferences = PreferenceManager.getDefaultSharedPreferences(this);
mCurrentValue = mSharedPreferences.getBoolean("my_preference",false);
Log.d(TAG, "onCreate:::: my_preference and mCurrentValue=" + mCurrentValue);
if(mCurrentValue){
// we have to use simple setTheme() instead getApplication.setTheme()!!!
setTheme(R.style.DarkTheme);
Log.d(TAG, "onCreate:::: setTheme:DarkTheme");
} else {
setTheme(R.style.LightTheme);
Log.d(TAG, "onCreate:::: setTheme:LightTheme");
}
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_settings);
Fragment preferenceFragment = new SettingsFragment();
getFragmentManager().beginTransaction().add(R.id.preference_container, preferenceFragment).commit();
}
// callback method for changing preference. It's called only if "my_preference" has changed
@Override
public void onXchange(Boolean value) {
// if value differs from previous Theme, we recreate Activity
Log.d(TAG, "onXchange:::: \n has called");
if (value!=mCurrentValue) {
Log.d(TAG, "onXchange:::: \n new value!=oldValue");
mCurrentValue=value;
recreate();
}
}
}
SettingsFragment类
public class SettingsFragment extends PreferenceFragment implements Preference.OnPreferenceChangeListener {
private static final String TAG = SettingsFragment.class.getSimpleName();
// declaring PreferenceXchangeListener
private PreferenceXchangeListener mPreferenceXchangeListener;
public SettingsFragment() {
}
// declaring PreferenceXchangeListener in order to communicate with Activities
public interface PreferenceXchangeListener {
void onXchange(Boolean value);
}
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
//Load the Preferences from the XML file
addPreferencesFromResource(R.xml.app_preferences);
CheckBoxPreference mCheckBoxPreference = (CheckBoxPreference)findPreference("my_preference");
mCheckBoxPreference.setOnPreferenceChangeListener(this);
}
@Override
public void onAttach(Context context) {
super.onAttach(context);
// on Attch we assign parent Activity as PreferenceXchangeListener
try {
mPreferenceXchangeListener = (PreferenceXchangeListener) context;
} catch (ClassCastException e) {
Log.e(TAG, "onAttach::::: PreferenceXchangeListener must be set in parent Activity");
}
}
@Override
public boolean onPreferenceChange(Preference preference, Object newValue) {
String preferenceKey=preference.getKey();
// only my_preference is checked in this case. Later you may add another behaviour to another preference change
if(preferenceKey.equals("my_preference")){
((CheckBoxPreference)preference).setChecked((Boolean)newValue);
// executing parent Activity's callback with the new value
mPreferenceXchangeListener.onXchange((Boolean)newValue);
return true;
}
// ... check other preferences here
return false;
}
}
答案 0 :(得分:1)
尝试一下:
public class SettingsFragment extends PreferenceFragment implements Preference.OnPreferenceChangeListener {
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
//Load the Preferences from the XML file
addPreferencesFromResource(R.xml.app_preferences);
// Find appropriate preference
CheckBoxPreference mThemePreference =(CheckBoxPreference)getPreferenceManager().findPreference("pref_pref1");
// we have to set up listener in order for persisting change to new value
mThemePreference.setOnPreferenceChangeListener(this);
SharedPreferences sharedPreferences = PreferenceManager.getDefaultSharedPreferences(mThemePreference.getContext());
Boolean value=sharedPreferences.getBoolean("pref_pref1",true);
onPreferenceChange(mThemePreference, value);
}
// overriding onPreferenceChange - if we return 'true', the preference will be persisted
@Override
public boolean onPreferenceChange(Preference preference, Object newValue) {
String preferenceKey = preference.getKey();
// we have to check the preference type and key, maybe later we have more preferences....
if(preference instanceof CheckBoxPreference){
if(preferenceKey.equals("pref_pref1")){
// Edited this line *******
((CheckBoxPreference)preference).setChecked((Boolean)newValue);
// ... do other preference related stuff here - if necessary, for example setSummary, etc...
}
}
return true;
}
}
简而言之:在您的PreferenceFragment中实现OnPreferenceChange。当您覆盖onPreferenceChane时,返回true。在这种情况下,较早的首选项将被覆盖。
希望对您有所帮助(如果是,请不要忘记接受我的回答)!
最好的祝福,
Cs
P.S:别忘了在模拟器上卸载应用
答案 1 :(得分:1)
好,这是工作版本:
1)在MainActivity.java的onCreate方法中检查当前主题,然后调用super.onCreate()和 setContentView()并将其添加到私有全局布尔变量中(让我们称之为mTheme)。更多信息:Change Activity's theme programmatically
2)在MainActivity.java的onStart()方法中,您应该检查设置是否已更改,因为从另一个Activity返回时不会调用onCreate。如果mTheme!= newSettingValue,则调用recreate()。重要说明:它类似于onDestroy方法,因此先前设置的值可能会丢失! https://developer.android.com/reference/android/app/Activity#recreate()
3)在您的SettingsFragment中,您必须使用update(Boolean value)方法定义一个接口(ThemeXchangeListener)。您还必须声明ThemeXchangeListener mListener字段。
4)在SettingsFragment的onAttach(Context context)方法中,将上下文分配给mListener-> mListener =(ThemeXchangeListener)context;
5)在SettingsFragment的onPreferenceChange(偏好设置,对象值)中,调用mListener.update((Boolean)value);
6)在SettingsActivity中声明布尔值,用于存储当前主题值(布尔mTheme)。在onCreate()中,加载首选项并为其分配值。 之前之前,super.onCreate()和setContentView()分配了适当的主题。
7)在SettingsActivity中实现ThemeXchangeListener并重写update(Boolean value)方法。如果value!= mTheme,则调用recreate()方法。 这将立即更新您的主题。
您可以在https://github.com/csongi77/UpdateThemeOnPreferenceChange
上查看完整的工作代码(带注释)。它在API15(IceCreamSandwich)的仿真器上可以正常工作。请让我知道它是否有效! 最好的祝福, Cs