仅在旧的Android设备(2.x)上我每次旋转模拟器时都会发生由stackoverflow引起的崩溃。如果我发表评论" preferenze()"模拟器不会崩溃,但应用程序不会保留新设置。这段代码可以创建无限循环吗?代码不正确吗?什么应该正确运行?谢谢!
private boolean preferencesChanged;
public void onCreate(Bundle savedInstanceState){
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
private void preferenze() {
SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(getBaseContext());
CheckboxPreference = prefs.getBoolean("checkboxPref", true);
ListPreference = prefs.getString("listpref", "");
numeronotifiche = prefs.getString("notify", "");
Sound = prefs.getString("sound", "");
barranotifiche = prefs.getBoolean("keep", false);
natura = prefs.getBoolean("suoninaturasino", false);
snatura = prefs.getString("suoninaturascelta", "");
snaturaold = prefs.getString("snaturaoldvalue", "");
if (snaturaold != snatura){
stopService(new Intent(this, UnUsedService.class));
}
SharedPreferences prefs2 = getSharedPreferences(PRIVATE_PREF, 0);
Editor editor10 = prefs2.edit();
editor10.putString("snaturaoldvalue", snatura);
editor10.commit();
// suoni attivati (o no)
if (natura){
startService(new Intent(this, UnUsedService.class));
}
else {
stopService(new Intent(this, UnUsedService.class));
}
if (barranotifiche){
showNotification();
}
else {
cancelNotification();
}
GestioneAllarme alarm = new GestioneAllarme();
if (CheckboxPreference){
if (numeronotifiche.equals("3")){
alarm.CancelAlarm(this);
alarm.SetAlarm3(this);
}
else if (numeronotifiche.equals("1")){
alarm.CancelAlarm(this);
alarm.SetAlarm1(this);
}
else if (numeronotifiche.equals("2")){
alarm.CancelAlarm(this);
alarm.SetAlarm2(this);
}
else {
//
}
}
else {
//
GestioneAllarme alarm2 = new GestioneAllarme();
alarm2.CancelAlarm(this);
}
//
if (Sound.equals("")){
Sound = "2";
Editor editor = prefs.edit();
editor.putString("sound", "2");
editor.commit();
}
if (ListPreference.equals("")){
ListPreference = "1500";
Editor editor = prefs.edit();
editor.putString("listpref", "1500");
editor.putInt("indexfade", 1500);
editor.commit();
}
if (numeronotifiche.equals("")){
numeronotifiche = "2";
Editor editor = prefs.edit();
editor.putString("numeronotifiche", "2");
editor.commit();
}
fade = Integer.parseInt(ListPreference);
notify = Integer.parseInt(numeronotifiche);
if (fade == 500){
animazione = R.style.MyCustomTheme1;
fadein = R.anim.fadein500;
fadeout = R.anim.fadeout500;
}
else if (fade == 1000){
animazione = R.style.MyCustomTheme2;
fadein = R.anim.fadein1000;
fadeout = R.anim.fadeout1000;
}
else if (fade == 1500){
animazione = R.style.MyCustomTheme3;
fadein = R.anim.fadein1500;
fadeout = R.anim.fadeout1500;
}
else if (fade == 2000){
animazione = R.style.MyCustomTheme4;
fadein = R.anim.fadein2000;
fadeout = R.anim.fadeout2000;
@Override
protected void onResume() {
super.onResume();
SharedPreferences sp = PreferenceManager.getDefaultSharedPreferences(this);
listener = new SharedPreferences.OnSharedPreferenceChangeListener() {
public void onSharedPreferenceChanged(SharedPreferences sharedPreferences, String key) {
preferencesChanged = true;
}
};
sp.registerOnSharedPreferenceChangeListener(listener);
protected void onStop(){
super.onStop();
if(preferencesChanged){
//Update the app
preferenze();
}
}
public class Preferences extends PreferenceActivity implements OnSharedPreferenceChangeListener{
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
addPreferencesFromResource(R.layout.preferences);
}
@Override
public void onSharedPreferenceChanged(SharedPreferences prefs, String listpref) {
答案 0 :(得分:1)
//这里有几个if / if else来改变值
这些句子可能会改变共享偏好,这反过来会激发你的听众,而听众又会调用preferenze
,......等等。如果这种情况持续下去,将抛出S.O.现在,根据条件,preferenze
方法只会读取但不会修改任何内容。在这种情况下,循环将结束。
关于仅在2.X设备中观察到的错误,可能是由于4.x设备更新,并且可能具有更多的RAM内存。
更新:
代码仍然不完整。看起来有两个活动:首先发布的活动和新发布的活动。我猜(这就是我可以用你发布的代码做的全部)你有PreferenceActivity
来显示设置并允许用户更改它们,并且监听器可以根据新的更新应用程序的其他部分设置。问题是,当调用侦听器时,它本身会修改设置,而这又会再次调用侦听器,这将再次修改首选项,依此类推。一旦堆耗尽内存,这将抛出一个SOException。
重新排列代码以解决此问题的方法是:
在您的活动的OnSharedPreferenceChangeListener
而不是onResume
中注册onCreate
,并使用onPause
方法取消注册(调用unregisterOnSharedPreferenceChangeListener
)。取消注册非常重要,因为我们不希望在用户离开屏幕后监听更改,或者系统重新创建活动(例如,当设备旋转时):
@Override
public void onCreate(Bundle savedInstanceState){
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
//We have removed the listener registration from here
}
@Override
protected void onResume() {
super.onResume();
SharedPreferences sp = PreferenceManager.getDefaultSharedPreferences(this);
listener = new SharedPreferences.OnSharedPreferenceChangeListener() {
public void onSharedPreferenceChanged(SharedPreferences prefs, String listpref) {
//I'll show what to do here in point 2.
}
};
sp.registerOnSharedPreferenceChangeListener(listener);
}
@Override
protected void onPause() {
super.onPause();
SharedPreferences sp = PreferenceManager.getDefaultSharedPreferences(this);
sp.unregisterOnSharedPreferenceChangeListener(listener);
}
使用当前代码,每次用户更改单个设置时,都会调用preferenze
方法来更新应用。因此,如果它改变5个字段,则该方法被调用5次。我们现在可以做的是只检查一次更改。我假设您不关心用户已更改了多少字段,因为您只需知道是否有更改。因此,在监听器中,您可以将布尔标志设置为true,而不是调用preferenze
:
public void onSharedPreferenceChanged(SharedPreferences sharedPreferences, String key) {
preferencesChanged = true;
}
好的,现在我们可以告诉您设置是否已更改。当用户完成并且活动即将关闭时,将按此顺序调用方法onPause
,onStop
和onDestroy
。您可以使用这些方法之一来检查布尔标志,并且只有在有更改时才更新应用程序。这样,如果用户更改了1,3或20个字段,我们将在最后更新应用程序一次。您可以在3种方法中的任何一种方法中执行此操作,但在取消注册侦听器(onPause
)之后执行此操作非常重要,否则您将再次遇到问题。例如:
protected void onStop(){
super.onStop();
...
if(preferencesChanged){
//Update the app
preferenze();
}
}
您可能需要更改一些内容,但总体而言您会明白这一点。
答案 1 :(得分:1)
似乎只要preferenze()
始终修改共享首选项,您就会有一个无限循环。
由于您没有发布完整的代码,因此很难说。但我想你的代码是这样的,它总是只在android 2.x上修改prefs
你可以尝试这样的事情以避免无限循环。
private boolean isPreferenzeRunning = false;
...
listener = new SharedPreferences.OnSharedPreferenceChangeListener() {
public void onSharedPreferenceChanged(SharedPreferences prefs, String listpref) {
if(!isPreferenzeRunning)preferenze();
}
};
...
private void preferenze()
isPreferenzeRunning = true;
try{
...
}finally{isPreferenzeRunning = false;}
}
答案 2 :(得分:1)
该代码甚至无法编译。
preferenze()
中的代码将返回首选项值(boolean,String,int等),而不是Preference对象。通过更改该方法中的值,您还将生成StackOverflowError
。
OnSharedPreferenceChangeListener
需要什么?