8

Sto implementando la mia sottoclasse DialogPreference personalizzata che ha un SeekBar utilizzato per mantenere un intero. Sono un po 'confuso su cosa deve andare in onSaveInstanceState() e onRestoreInstanceState(). In particolare, è necessario aggiornare il widget dell'interfaccia utente con cui l'utente interagisce (nel mio caso, il widget SeekBar) in onRestoreInstanceState()?Come implementare correttamente onRestoreInstanceState() per una sottoclasse DialogPreference?

La ragione per cui mi sono confuso è che l'articolo API doc here ti dice di fare questo:

@Override 
protected Parcelable onSaveInstanceState() { 
    final Parcelable superState = super.onSaveInstanceState(); 
    if (isPersistent()) { 
     return superState; 
    } 

    final SavedState myState = new SavedState(superState); 
    myState.value = mNewValue; //<------------ saves mNewValue 
    return myState; 
} 

@Override 
protected void onRestoreInstanceState(Parcelable state) { 
    if (state == null || !state.getClass().equals(SavedState.class)) { 
     super.onRestoreInstanceState(state); 
     return; 
    } 

    SavedState myState = (SavedState) state; 
    super.onRestoreInstanceState(myState.getSuperState()); 
    mNumberPicker.setValue(myState.value); //<------------ updates the UI widget, not mNewValue! 
} 

Ma guardando il sorgente per alcune classi privilegiate Android ufficiali (EditTextPreference e ListPreference), il widget UI è non aggiornato in onRestoreInstanceState(). Solo il valore sottostante della preferenza è (nell'esempio sopra, che sarebbe mNewValue).

Qui è la fonte rilevante per EditTextPreference:

@Override 
protected Parcelable onSaveInstanceState() { 
    final Parcelable superState = super.onSaveInstanceState(); 
    if (isPersistent()) { 
     return superState; 
    } 

    final SavedState myState = new SavedState(superState); 
    myState.value = getValue(); //<---- saves mValue 
    return myState; 
} 

@Override 
protected void onRestoreInstanceState(Parcelable state) { 
    if (state == null || !state.getClass().equals(SavedState.class)) { 
     super.onRestoreInstanceState(state); 
     return; 
    } 

    SavedState myState = (SavedState) state; 
    super.onRestoreInstanceState(myState.getSuperState()); 
    setValue(myState.value); //<---- updates mValue, NOT the UI widget! 
} 

Allora, qual è il consenso? Dove dovrei aggiornare il widget UI (se devo aggiornarlo del tutto ...)?

risposta

4

Ok, dopo alcuni esperimenti, sembra che l'aggiornamento del widget UI all'interno di onRestoreInstanceState() non sia la strada da percorrere, perché a quel punto sembra sempre essere null. Non so perché lo suggeriscono. Forse devi farlo se sottoclassi Preferenza, ma ci sono regole diverse da seguire quando sottoclassi DialogPreference ...? Questo spiegherebbe almeno perché ListPreference e EditTextPreference non lo fanno, perché sottoclasse DialogPreference.

Infatti, da quello che ho trovato, il widget UI non ha bisogno di essere aggiornato affatto! Dovrebbe avere i propri metodi di salvataggio/ripristino che gestiscono la gestione dello stato per te. Ad esempio, ecco un estratto di una sottoclasse DialogPreference che ho fatto con un widget SeekBar in esso:

@Override 
protected Parcelable onSaveInstanceState() { 
    final Parcelable superState = super.onSaveInstanceState(); 

    final SavedState myState = new SavedState(superState); 
    myState.maxValue = getMaxValue(); //<---- saves mMaxValue 
    myState.value = getValue(); //<---- saves mValue 
    return myState; 
} 

@Override 
protected void onRestoreInstanceState(Parcelable state) { 
    if (state == null || !state.getClass().equals(SavedState.class)) 
    { 
     super.onRestoreInstanceState(state); 
     return; 
    } 

    SavedState myState = (SavedState) state; 
    setMaxValue(myState.maxValue); //<---- updates mMaxValue 
    setValue(myState.value); //<---- updates mValue 
    super.onRestoreInstanceState(myState.getSuperState()); 
} 

Come potete vedere, non ho mai aggiornare un widget SeekBar ovunque. SeekBar salverà/ripristinerà il suo stato tutto da solo!

Noterai inoltre che ci sono alcune piccole deviazioni rispetto a quanto suggerito nei documenti per sviluppatori Android. Non controllo se DialogPreference è persistente prima di salvare lo stato, poiché in tal caso le proprietà mValue e mMaxValue non vengono salvate se lo sono. Io chiamo anche super.onRestoreInstanceState() proprio alla fine, come ho scoperto che non funziona mai quando viene chiamato in precedenza.

Queste sono solo le mie scoperte finora. Non sono sicuro di quale sia la strada giusta, ma quello che ho sopra sembra funzionare.

AGGIORNAMENTO: @whatyouhide vuole sapere quali sono i metodi setValue e setMaxValue nella sottoclasse DialogPreference. Eccoli:

public void setValue(int value) 
{ 
    value = Math.max(Math.min(value, mMaxValue), mMinValue); 

    if (value != mValue) 
    { 
     mValue = value; 
     persistInt(value); 
     notifyChanged(); 
    } 
} 

public void setMaxValue(int maxValue) 
{ 
    mMaxValue = maxValue; 
    setValue(Math.min(mValue, mMaxValue)); 
} 
+0

I metodi 'setValue' e' setMaxValue' che hai definito nel tuo 'DialogPreference 'personalizzato? In tal caso potresti pubblicare il codice per questi metodi? – whatyouhide

+0

@whatyouhide Sì. Vedi la mia risposta aggiornata. –

+0

Mmmm, grazie. Il mio problema è che il mio 'DialogPreference.getValue()' recupera il valore da alcuni 'View's all'interno della finestra di dialogo, e quelle viste sono ancora puntatori' nulli' quando vengono richiamati 'onSaveInstanceState' e' onRestoreInstanceState'. – whatyouhide

Problemi correlati