1

仅在旧的 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) {
4

3 回答 3

1

// 这里有几个 if/if else 来改变值

这些句子可能会更改共享首选项,这反过来会触发您的听众,而听众又会调用preferenze,...,等等。如果这种情况永远持续下去,就会抛出一个 SO。现在根据条件,该preferenze方法可能只读取但不修改任何内容。在这种情况下,循环将结束。

关于仅在 2.X 设备中观察到的错误,这可能是由于 4.x 设备更新且可能具有更多 RAM 内存。


更新:
代码仍然不完整。看起来有两个活动:您首先发布的活动和新的活动。我想(这就是我对您发布的代码所能做的全部)您必须PreferenceActivity显示设置并允许用户更改它们,并且侦听器可以根据新设置更新应用程序的其他部分。问题是当监听器被调用时,它本身会修改设置,而这又会再次调用监听器,这将再次修改首选项,以此类推。一旦堆内存不足,这将引发 SOException。

重新排列代码以解决此问题的一种方法是:

  1. OnSharedPreferenceChangeListener在您的活动中注册,onResume而不是onCreateonPause方法中取消注册(调用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);
        }
    
  2. 使用您当前的代码,每次用户更改单个设置时,preferenze都会调用该方法来更新应用程序。因此,如果它更改 5 个字段,则该方法被调用 5 次。我们现在可以做的是只检查一次更改。我假设您不在乎用户更改了多少字段,因为您只需要知道是否有更改。因此,在侦听器中preferenze,您可以将布尔标志设置为 true,而不是调用:

        public void onSharedPreferenceChanged(SharedPreferences sharedPreferences, String key) {
            preferencesChanged = true;
        }
    
  3. 好的,现在我们有一种方法可以判断设置是否已更改。当用户完成并且活动即将关闭时,方法onPauseonStoponDestroy按此顺序调用。您可以使用其中一种方法来检查布尔标志,并且只有在发生更改时才更新应用程序。这样,如果用户更改了 1、3 或 20 个字段,我们将在最后只更新一次应用程序。您可以在 3 种方法中的任何一种中执行此操作,但在取消注册侦听器 ( onPause) 之后执行此操作非常重要,否则您将再次遇到问题。例子:

        protected void onStop(){
            super.onStop();
            ...
    
            if(preferencesChanged){
                //Update the app
                preferenze();
            }
        }
    

你可能需要改变一些东西,但总的来说你明白了。

于 2013-01-10T12:36:07.500 回答
1

似乎只要preferenze()始终修改共享首选项,您就会陷入无限循环。

由于您没有发布完整的代码,因此很难说。但我猜你的代码是这样的,它总是只在 android 2.x 上修改首选项

你可以尝试这样的事情来避免无限循环。

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;}       
} 
于 2013-01-10T12:38:15.823 回答
1

该代码甚至无法编译。

中的代码preferenze()将返回首选项值(布尔值、字符串、整数等),而不是首选项对象。通过更改该方法中的值,您还将导致StackOverflowError.

需要什么OnSharedPreferenceChangeListener

于 2013-01-10T12:38:32.273 回答