8

Implementuję własną niestandardową podklasę DialogPreference, która ma SeekBar używaną do utrzymywania liczby całkowitej. Jestem trochę zdezorientowany tym, co musi przejść w onSaveInstanceState() i onRestoreInstanceState(). W szczególności, czy musisz zaktualizować widget interfejsu użytkownika, z którym użytkownik wchodzi w interakcję (w moim przypadku widżet SeekBar) w wersji onRestoreInstanceState()?Jak poprawnie wdrożyć onRestoreInstanceState() dla podklasy DialogPreference?

Powodem Jestem zmieszany jest to, że artykuł API doc here mówi ci to zrobić:

@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! 
} 

Ale patrząc na źródło dla niektórych oficjalnych Android klas Garaż (EditTextPreference i ListPreference), widżet UI jest niezaktualizowany w onRestoreInstanceState(). Jedyną podstawową wartością preferencji jest (w powyższym przykładzie będzie to mNewValue).

Oto istotne źródło 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! 
} 

Więc, co jest konsensus? Gdzie mam zaktualizować widget UI (jeśli mam go w ogóle zaktualizować ...)?

Odpowiedz

4

Po przeprowadzeniu niektórych eksperymentów wygląda na to, że aktualizacja widgetu interfejsu użytkownika w wersji onRestoreInstanceState() nie jest dobrym rozwiązaniem, ponieważ w tym momencie zawsze wydaje się być null. Nie wiem, dlaczego to sugerują. Być może musisz to zrobić, jeśli podklasy Preference, ale istnieją różne zasady przestrzegać podklasy DialogPreference ...? To by wyjaśniało przynajmniej, dlaczego ListPreference i EditTextPreference tego nie robią, ponieważ podklasy DialogPreference.

W rzeczywistości, z tego co znalazłem, widget UI wcale nie musi być aktualizowany! Powinien mieć własne metody zapisu/przywracania, które obsługują zarządzanie stanem. Na przykład, oto fragment podklasy DialogPreference zrobiłem z widgetu SeekBar w nim:

@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()); 
} 

Jak widać, nie mogę zaktualizować widget SeekBar wszędzie. SeekBar sam zachowa/przywróci swój stan!

Zauważysz również, że są pewne niewielkie odchylenia od tego, co sugerują dokumenty dla programistów Androida. Nie sprawdzam, czy dialog DialogPreference jest trwały przed zapisaniem stanu, ponieważ wtedy właściwości nie zostaną zapisane, jeśli tak jest. Na koniec również nazywam się super.onRestoreInstanceState(), ponieważ stwierdziłem, że nigdy nie działa, gdy jest wywoływane wcześniej.

To tylko moje odkrycia do tej pory. Nie jestem pewien, jaka jest właściwa droga, ale wydaje mi się, że to, co mam powyżej, działa.

AKTUALIZACJA: @whatyouhide chce wiedzieć, jak wyglądają metody setValue i setMaxValue w mojej podklasie DialogPreference. Oto one:

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

Czy zdefiniowano metody 'setValue' i' setMaxValue' w niestandardowym 'DialogPreference'? Jeśli tak, czy mógłbyś opublikować kod dla tych metod? – whatyouhide

+0

@whatyouhide Tak. Zobacz moją zaktualizowaną odpowiedź. –

+0

Mmmm, dziękuję. Mój problem polega na tym, że moje 'DialogPreference.getValue()' pobiera wartość z niektórych 'View's wewnątrz okna dialogowego, a te widoki są nadal wskaźnikami' null' gdy wywoływane są 'onSaveInstanceState' i' onRestoreInstanceState'. – whatyouhide