2013-10-21 19 views
5

the Android guideによれば、私はPreference Fragmentsを使ってプリファレンスを実装しようとしています。あるpreferences.xmlでは私が宣言:SwitchPreferencesはonPreferenceChange()メソッドを複数回呼び出します

<SwitchPreference 
     android:key="enable_wifi" 
     android:title="Enable WiFi" 
     /> 

とクラスthahにおけるよりは私のonCreateメソッドでPreferenceFragmentを拡張:

public class FragmentSettings extends PreferenceFragment { 

@Override 
public void onCreate(Bundle savedInstanceState) { 
    super.onCreate(savedInstanceState); 

    addPreferencesFromResource(R.xml.preferences); 

    mEnableWifi = (SwitchPreference) findPreference(enable_wifi); 
    mEnableWiFi.setOnPreferenceChangeListener(new OnPreferenceChangeListener() { 

    @Override 
    public boolean onPreferenceChange(Preference preference, Object newValue) { 

     Log.i(getClass().getName(), preference.getKey() 
      + String.valueOf(newValue)); 
    } 
} 

そして、私はSwitchPrefereneにCLIKまたはログ・ショー内で切り替えたときに私が得た結果、

enable_wifi false 
enable_wifi false 
enable_wifi true 
enable_wifi true 

ですから、私はリスナーが複数回呼び出されると思います。どのようにそれを扱うか、それを修正する?

答えて

1

OPのコードにonPreferenceChangeの返信文がありません。

最後にreturn true;を呼び出していることを確認してください。実際には環境設定が変更されています。

しかし問題は、それが不必要に更新されませんので、設定変更リスナーの内部でチェックを行い解決しない場合:

@Override 
public boolean onPreferenceChange(Preference preference, Object newValue) { 
    if (preference.isEnabled() != newValue) { 
     // Do something on normal switch 
     return true; 
    } else { 
     // Preference wasn't changed, do nothing and don't update it 
     return false; 
    } 
} 
+0

問題が「return」ステートメントが見つからなかった場合、コードはコンパイルされますか?ログは、コードがうまくコンパイルされることを示します。 – Vikram

+0

@Vikram return文が見つからない場合、多分何かがありますか?問題がどこにあるのか、どうすればわかるのでしょうか?私たちができることは、次に推測することです:-) – Simas

+0

私はあなたに絶対に同意します - 問題がどこにあるかを伝えるのは難しいです。私は、コードが欠落したreturn文でコンパイルされないと言っていただけです。それはいいけどね:) – Vikram

11

それはSwitchPreference実装にバグによるものです。

コールバックonPreferenceChangeが呼び出されます。

  • 初回だけSharedPreference更新TwoStatePreference.onClick方法で。
  • Switchウィジェットのトグル状態で2回目です。 Hereが呼び出されます。

ロジックにはコメントできませんが、少なくともフレームワークでは状態に変更があった場合にのみonPreferenceChangeコールバックを呼び出す必要があります。責任は私たちにあります。 SwitchPreference.isCheckedメソッドを使用して、状態が変更されたかどうかを確認します。ここで

public boolean onPreferenceChange(Preference preference, Object newValue) {  
    if(((SwitchPreference) preference).isChecked() != (Boolean) newValue) { 
     // State got changed 
     Log.i("Testing", preference.getKey() + " : " + String.valueOf(newValue)); 

     // If you don't want to save the preference change return false from this if block. 
    }    
    return true; 
} 

はあなたの参照のためのコールスタックです:

TwoStatePreference.onClick:

MainActivity$SettingsFragment$1.onPreferenceChange(Preference, Object) line: 45 
SwitchPreference(Preference).callChangeListener(Object) line: 895 
SwitchPreference(TwoStatePreference).onClick() line: 65 
SwitchPreference(Preference).performClick(PreferenceScreen) line: 950 
PreferenceScreen.onItemClick(AdapterView, View, int, long) line: 215  
ListView(AdapterView).performItemClick(View, int, long) line: 298 
ListView(AbsListView).performItemClick(View, int, long) line: 1100 
AbsListView$PerformClick.run() line: 2788 
AbsListView$1.run() line: 3463 
Handler.handleCallback(Message) line: 730 
ViewRootImpl$ViewRootHandler(Handler).dispatchMessage(Message) line: 92 
Looper.loop() line: 137 

スイッチのウィジェットトグル:

MainActivity$SettingsFragment$1.onPreferenceChange(Preference, Object) line: 45 
SwitchPreference(Preference).callChangeListener(Object) line: 895 
SwitchPreference$Listener.onCheckedChanged(CompoundButton, boolean) line: 47  
Switch(CompoundButton).setChecked(boolean) line: 126  
Switch.setChecked(boolean) line: 666  
SwitchPreference.onBindView(View) line: 106 
0

は、フラグメントのオブジェクトがで開催されているかもしれませそれが破壊されても記憶する。したがって、フラグメントが再び作成されるとき、前のフラグメントからのリスナーはまだ存在し、表示されるコールバックは2つの異なるリスナーからのものである可能性があります。呼び出しが実際には2つの異なるリスナーからのものであることを確認するには、オブジェクトのtoStringメソッドを印刷してみてください。

@Override 
public boolean onPreferenceChange(Preference preference, Object newValue) { 
    Log.i(getClass().getName(), preference.getKey() + String.valueOf(newValue)); 
    Log.i(getClass().getName(), this.toString()); 
} 

あなたがのtoStringのために別の値を取得する場合、私は、フラグメントのonDestoryでリスナーを削除すると、あなたのための問題を解決するかもしれないと思います。

@Override 
public void onDestroy() { 
    super.onDestroy(); 
    mEnableWifi.setOnPreferenceChangeListener(null); 
} 
関連する問題