簡體   English   中英

此代碼段是否會導致無限循環或其他?

[英]Does this snippet cause an infinite loop or other?

只有舊的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) {

//這里有幾個if / if else來改變值

這些句子可能會改變共享首選項,這反過來會激發你的聽眾,而反過來會調用preferenze ,......等等。 如果這種情況持續下去,就會拋出一個SO。 現在,根據條件,可能會發生preferenze方法只讀取但不修改任何內容。 在這種情況下,循環將結束。

關於僅在2.X設備中觀察到的錯誤,可能是由於4.x設備更新,並且可能具有更多RAM內存。


更新:
代碼仍然不完整。 看起來有兩個活動:首先發布的活動和新發布的活動。 我猜(這就是我可以用你發布的代碼做的全部)你有一個PreferenceActivity來顯示設置並允許用戶更改它們,並且監聽器可以根據新的設置更新應用程序的其他部分。 問題是,當調用偵聽器時,它本身會修改設置,而這又會再次調用偵聽器,這將再次修改首選項,依此類推。 一旦堆耗盡內存,這將拋出SOException。

重新排列代碼以解決此問題的方法是:

  1. 在活動的onResume而不是onCreate注冊OnSharedPreferenceChangeListener ,並在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(); } } 

您可能需要更改一些內容,但總體而言您會得到這個想法。

看來,只要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;}       
} 

該代碼甚至不會編譯。

preferenze()的代碼將返回首選項值(boolean,String,int等),而不是Preference對象。 通過更改該方法中的值,您還將導致StackOverflowError

OnSharedPreferenceChangeListener什么需要?

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM