2013-10-21 213 views
5

根據the Android guide我試圖使用偏好片段實現首選項。在我的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或交換機內部日誌顯示

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

我絕對同意你 - 很難說出問題在哪裏。我只想說,代碼不會編譯時會丟失返回語句。雖然這是一個很好的抓住:)) – Vikram

11

這是由於SwitchPreference執行錯誤。

回調onPreferenceChange被稱爲:

  • 首次由TwoStatePreference.onClick方法,剛剛更新SharedPreference
  • 第二次由Switch小部件的切換狀態。它被調用。

無法評論邏輯,但至少只有在狀態發生變化時框架才應該調用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

可能是片段的對象是在正在舉行記憶,即使它被毀壞。所以當再次創建片段時,前一個片段的偵聽器仍然存在,您看到的回調可能來自兩個不同的偵聽器。爲了確認調用確實來自兩個不同的監聽器,請嘗試打印該對象的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); 
}