此代码段是否会导致无限循环或其他?

时间:2013-01-10 12:30:55

标签: java android

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

3 个答案:

答案 0 :(得分:1)

  

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

这些句子可能会改变共享偏好,这反过来会激发你的听众,而听众又会调用preferenze,......等等。如果这种情况持续下去,将抛出S.O.现在,根据条件,preferenze方法只会读取但不会修改任何内容。在这种情况下,循环将结束。

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


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

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

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

        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();
            }
        }
    
  4. 您可能需要更改一些内容,但总体而言您会明白这一点。

答案 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需要什么?