Ustawienia – PreferenceActivity – #12

Dobrze, że przeczytałam dokumentację Androida zanim zabrałam się za implementację ustawień użytkownika za pomocą Shared Preferenced:

This class shows you how to use the SharedPreferences APIs to store and retrieve simple values.

Note: The SharedPreferences APIs are only for reading and writing key-value pairs and you should not confuse them with the Preference APIs, which help you build a user interface for your app settings (although they use SharedPreferences as their implementation to save the app settings). For information about using the Preference APIs, see the Settings guide.

Skoro już wiedziałam czego nie używać mogłam zagłębić się w implementację 😉 A ta nie była łatwa… Po połączeniu wiedzy z kilku źródeł (dokumentacjastackOverflow) udało mi się stworzyć coś co działa. Na ten moment są dwa ustawienia:

wp-1492348819802.

Do menu na głównym ekranie dodałam pozycję z ustawieniami:

wp-1492348810516.


<item
android:id="@+id/settings_item"
android:title="@string/settings"
app:showAsAction="never" />

view raw

main_menu.xml

hosted with ❤ by GitHub

I switch z funkcji onOptionsItemSelected wzbogacił się o jeszcze jeden case:


@Override
public boolean onOptionsItemSelected(MenuItem item) {
switch (item.getItemId()) {
/* … */
case R.id.settings_item:
Intent settingsIntent = new Intent(this, SettingsActivity.class);
startActivity(settingsIntent);
return true;
/* … */
}
}

Tu jeszcze nie było żadnych problemów, kod jak kod. XML z ustawieniami też normalny w sumie:


<?xml version="1.0" encoding="utf-8"?>
<PreferenceScreen xmlns:android="http://schemas.android.com/apk/res/android">
<ListPreference
android:key="PREFS_FIRST_DAY"
android:title="@string/first_day"
android:summary="Obecny początek tygodnia: %s"
android:entries="@array/week_days_list_preference"
android:entryValues="@array/week_days_entryvalues_list_preference"
android:defaultValue="7" />
<EditTextPreference
android:key="PREFS_DAYS_NO"
android:title="@string/days_no"
android:summary=""
android:inputType="number"
android:defaultValue="7" />
</PreferenceScreen>

view raw

preferences.xml

hosted with ❤ by GitHub

Jedno ustawienie jako wybieranie z listy dostępnych wartości, drugie wpisujemy jako zwykły tekst:

Ciekawostką tutaj jest to, że jeśli używamy listPreference i w summary umieścimy „%s” to wyświetli nam się aktualnie wybrana wartość. Niestety nie jest to spójne i nad aktualizacją i wyświetlaniem długości tygodnia jeszcze pracuję, bo ustawia się tylko w momencie zmiany.

Dni tygodnia i wartości przechowuję w arrays.xml:


<string-array name="week_days_list_preference">
<item>@string/monday</item>
<item>@string/tuesday</item>
<item>@string/wednesday</item>
<item>@string/thursday</item>
<item>@string/friday</item>
<item>@string/saturday</item>
<item>@string/sunday</item>
</string-array>
<string-array name="week_days_entryvalues_list_preference">
<item>2</item>
<item>3</item>
<item>4</item>
<item>5</item>
<item>6</item>
<item>7</item>
<item>1</item>
</string-array>

view raw

arrays.xml

hosted with ❤ by GitHub

Schody zaczęły się przy SettingsActivity od razu z klasą SettingsFragment:


public class SettingsActivity extends PreferenceActivity {
final static String PREFS_FIRST_DAY = "PREFS_FIRST_DAY";
final static String PREFS_DAYS_NO = "PREFS_DAYS_NO";
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
getFragmentManager().beginTransaction()
.replace(android.R.id.content, new SettingsFragment())
.commit();
PreferenceManager.setDefaultValues(this, R.xml.preferences, false);
}
public static class SettingsFragment extends PreferenceFragment {
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(this.getActivity());
SharedPreferences.OnSharedPreferenceChangeListener listener = new SharedPreferences.OnSharedPreferenceChangeListener() {
public void onSharedPreferenceChanged(SharedPreferences prefs, String key) {
Preference pref = findPreference(key);
if (pref instanceof EditTextPreference) {
EditTextPreference editTextPreference = (EditTextPreference) pref;
pref.setSummary(editTextPreference.getText());
}
MainActivity.preferenceChanged = true;
}
};
prefs.registerOnSharedPreferenceChangeListener(listener);
addPreferencesFromResource(R.xml.preferences);
}
}
}

Dużo czasu i prób zajęło mi ogarnięcie listenera, który śledził zmianę wartości ustawień. Wymyśliłam sobie jeszcze, że w momencie jak użytkownik zmieni ustawienia to powinien mu się przeładować główny ekran. W MainActivity stworzyłam metodę onResume, która uruchamia się w momencie kiedy użytkownik wraca na główny ekran. Dorzuciłam jeszcze statyczną globalną zmienną, którą ustawiam w momencie kiedy zmieniam ustawienia, żeby nie przeładowywać ekranu niepotrzebnie.


@Override
protected void onResume() {
super.onResume();
if (preferenceChanged) {
preferenceChanged = false;
recreate();
}
}

Pozostało jeszcze wykorzystać te ustawienia do pobierania listy obiadów z bazy i wyświetlania ich na głównym ekranie. W tym celu na wydzieliłam sobie klasę TimeUtils.java z metodami:


public static int getTimeDeltaMilliseconds(Context context) {
return 1000 * 60 * 60 * 24 * getDaysInPlanner(context);
}
public static int getDaysInPlanner(Context context) {
SharedPreferences sharedPref = PreferenceManager.getDefaultSharedPreferences(context);
String daysNoPrefs = sharedPref.getString(SettingsActivity.PREFS_DAYS_NO, "7");
return Integer.parseInt(daysNoPrefs);
}
private static int getFirstDay(Context context) {
SharedPreferences sharedPref = PreferenceManager.getDefaultSharedPreferences(context);
String firstDayPrefs = sharedPref.getString(SettingsActivity.PREFS_FIRST_DAY, "7");
return Integer.parseInt(firstDayPrefs);
}

view raw

TimeUtils.java

hosted with ❤ by GitHub

Tam gdzie do tej pory sprawdzaliśmy czy dzień dzisiejszy jest sobotą teraz sprawdzamy czy jest tym dniem, który użytkownik wyznaczył sobie jako pierwszy dzień tygodnia. Z kolei pętla, która szła przez 7 dni, teraz idzie przez tyle dni ile określił użytkownik. Potrzeba skorzystania ze zmiennej Context spowodowała, że musiałam przeorać się przez aplikację, zastanawiam się, czy nie należało stworzyć tego jako pola w klasie i nie ustawiać tego w momencie inicjalizacji klasy, ale to materiał do przemyśleń w trakcie refaktoryzacji 😉

Wesołych Świąt jeśli ktoś tu dotarł 😉

Dodaj komentarz

Twój adres e-mail nie zostanie opublikowany. Wymagane pola są oznaczone *

This site uses Akismet to reduce spam. Learn how your comment data is processed.