1

古いAndroidデバイス(2.x)でのみ、エミュレーターを回転させるたびにスタックオーバーフローが原因でクラッシュします。「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/ifelse値を変更します

これらの文はおそらく共有設定を変更し、リスナーを起動し、リスナーはpreferenze、...などを呼び出します。これが永遠に続く場合、SOがスローされます。条件によっては、preferenzeメソッドが読み取りのみを行い、何も変更しない場合があります。この場合、ループは終了します。

また、2.Xデバイスでのみ観察されるエラーについては、4.xデバイスがより新しく、おそらくより多くのRAMメモリを搭載していることが原因である可能性があります。


更新:
コードはまだ不完全です。最初に投稿したアクティビティと新しいアクティビティの2つのアクティビティがあるようです。おそらく(投稿したコードでできることはこれだけです)PreferenceActivity、設定を表示してユーザーが変更できるようにする必要があります。リスナーは、新しい設定に従ってアプリケーションの他の部分を更新するためにそこにいます。問題は、リスナーが呼び出されると、リスナー自体が設定を変更し、これによりリスナーが再度呼び出され、設定が再度変更されるということです。ヒープのメモリが不足すると、これによりSOExceptionがスローされます。

これを解決するためにコードを再配置する方法は次のとおりです。

  1. の代わりにをOnSharedPreferenceChangeListenerアクティビティに登録し、メソッドの登録を解除します(を呼び出します)。ユーザーが画面を離れた後、またはアクティビティがシステムによって再作成された後(たとえば、デバイスが回転したとき)に変更をリッスンしたくないため、登録解除は非常に重要です。onResumeonCreateonPauseunregisterOnSharedPreferenceChangeListener

        @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. 現在のコードでは、ユーザーが1つの設定を変更するたびにpreferenze、アプリを更新するためにメソッドが呼び出されます。したがって、5つのフィールドを変更すると、メソッドは5回呼び出されます。今できることは、変更を1回だけチェックすることです。必要なのは変更があるかどうかを知ることだけなので、ユーザーが変更したフィールドの数は気にしないと思います。したがって、リスナーでは、を呼び出す代わりにpreferenze、ブールフラグをtrueに設定できます。

        public void onSharedPreferenceChanged(SharedPreferences sharedPreferences, String key) {
            preferencesChanged = true;
        }
    
  3. これで、設定が変更されたかどうかを確認する方法ができました。ユーザーが完了し、アクティビティが閉じられようとしているとき、メソッドonPauseonStopおよびonDestroyはこの順序で呼び出されます。これらの方法のいずれかを使用してブールフラグを確認し、変更がある場合にのみアプリを更新できます。このように、ユーザーが1、3、または20フィールドを変更した場合、最後に1回だけアプリを更新します。これは3つの方法のいずれでも実行できますが、リスナーの登録を解除した後にこれを実行することが非常に重要です(onPause)。そうしないと、再び問題が発生します。例:

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

あなたはいくつかのことを変える必要があるかもしれませんが、全体的にあなたは考えを理解します。

于 2013-01-10T12:36:07.500 に答える
1

preferenze()共有設定を常に変更するとすぐに、無限ループが発生するようです。

あなたは完全なコードを投稿しなかったので、言うのは難しいです。しかし、あなたのコードは、Android2.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()、Preferenceオブジェクトではなく、preference値(boolean、String、intなど)を返します。そのメソッドの値を変更することにより、も発生しStackOverflowErrorます。

の必要性は何OnSharedPreferenceChangeListenerですか?

于 2013-01-10T12:38:32.273 に答える