반응형
블로그 이미지
개발자로서 현장에서 일하면서 새로 접하는 기술들이나 알게된 정보 등을 정리하기 위한 블로그입니다. 운 좋게 미국에서 큰 회사들의 프로젝트에서 컬설턴트로 일하고 있어서 새로운 기술들을 접할 기회가 많이 있습니다. 미국의 IT 프로젝트에서 사용되는 툴들에 대해 많은 분들과 정보를 공유하고 싶습니다.
솔웅

최근에 받은 트랙백

글 보관함


이번엔 Settings 를 꾸밀 겁니다.


Setting 관련 한 Android Developer API Guide는 여기에 있습니다.

SharedPreference API


이 Sunshine  앱에서는 Setting UX 가 아래와 같이 진행 될 겁니다.



우편번호를 입력하는 화면과 화씨/섭씨 를 선택할 수 있는 기능을 제공할 겁니다.


먼저 SettingsActivity를 생성합니다.


안드로이드 버전에 따라 PreferenceActivity와 PreferenceFragment를 사용합니다.



이렇게 SettingsActivity.java  를 생성합니다.


public class SettingsActivity extends PreferenceActivity
        implements Preference.OnPreferenceChangeListener {

    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        // Add 'general' preferences, defined in the XML file
        addPreferencesFromResource(R.xml.pref_general);

        // For all preferences, attach an OnPreferenceChangeListener so the UI summary can be
        // updated when the preference changes.
        bindPreferenceSummaryToValue(findPreference(getString(R.string.pref_location_key)));
        bindPreferenceSummaryToValue(findPreference(getString(R.string.pref_units_key)));
    }

    /**
     * Attaches a listener so the summary is always updated with the preference value.
     * Also fires the listener once, to initialize the summary (so it shows up before the value
     * is changed.)
     */
    private void bindPreferenceSummaryToValue(Preference preference) {
        // Set the listener to watch for value changes.
        preference.setOnPreferenceChangeListener(this);

        // Trigger the listener immediately with the preference's
        // current value.
        onPreferenceChange(preference,
                PreferenceManager
                        .getDefaultSharedPreferences(preference.getContext())
                        .getString(preference.getKey(), ""));
    }

    @Override
    public boolean onPreferenceChange(Preference preference, Object value) {
        String stringValue = value.toString();

        if (preference instanceof ListPreference) {
            // For list preferences, look up the correct display value in
            // the preference's 'entries' list (since they have separate labels/values).
            ListPreference listPreference = (ListPreference) preference;
            int prefIndex = listPreference.findIndexOfValue(stringValue);
            if (prefIndex >= 0) {
                preference.setSummary(listPreference.getEntries()[prefIndex]);
            }
        } else {
            // For other preferences, set the summary to the value's simple string representation.
            preference.setSummary(stringValue);
        }
        return true;
    }

}


PreferenceActivity를 extends 하고 Preference.OnPreferenceChangeListener 를 implements 합니다.

처음 onCreate() 메소드에서는 해당 preference xml을 불러옵니다.
그리고 나서 Listener를 구현해서 해당 Preference에 어떤 변화가 있을 때 UI Summary를 update 할 수 있도록 합니다.

그 구체적인 내용은 bindPreferenceSummaryToValue()에 구현해 놓습니다.

그리고 Override한 onPreferenceChange()메소드가 있습니다.

여기에서는 ListPreference일 경우 해당하는 아이템을 고르도록 하고 그렇지 않은 경우는 그냥 Summary를 가져 오도록 합니다.

이렇게 되면 사용자가 우편번호를 바꾸거나 섭씨/화씨 조건을 바꿨을 때 그에 해당하는 값을 가져올 수 있게 됩니다.


이렇게 SettingsActivity  클래스를 만들었으면 이를 AndroidManifest에 등록해야 합니다.


        <activity
            android:name=".SettingsActivity"
            android:label="@string/title_activity_settings"
            android:parentActivityName=".MainActivity" >
            <meta-data
                android:name="android.support.PARENT_ACTIVITY"
                android:value="com.example.android.sunshine.app.MainActivity" />
        </activity>


label은  string xml에 지정해 놓은 값을 사용합니다.

그리고 parentActivityName은 MainActivity로 합니다.

이렇게 되면 Back  버튼을 누르게 되면 MainActivity로 가게 됩니다.


이제 MainActivity에서도 약간 손을 좀 봐야 하는데요.


onOptionsItemSelected()를 아래와 같이 코딩합니다.


    @Override
    public boolean onOptionsItemSelected(MenuItem item) {
        // Handle action bar item clicks here. The action bar will
        // automatically handle clicks on the Home/Up button, so long
        // as you specify a parent activity in AndroidManifest.xml.
        int id = item.getItemId();

        //noinspection SimplifiableIfStatement
        if (id == R.id.action_settings) {
            startActivity(new Intent(this, SettingsActivity.class));
            return true;
        }

        return super.onOptionsItemSelected(item);
    }


Option item이 선택 됐을 경우 이것이 action_settings일 경우 SettingsActivity를 실행하도록 Intent를 사용합니다.


여기까지 하면 MainActivity에서 Setting를 선택하면 SettingsActivity  화면으로 넘어가게 됩니다.

아직 빈화면만 보일 겁니다.


DetailActivity에서도 이 onOptionsItemSelected()를 똑 같이 구현해 놓으면 이곳에서도 Settings를 선택하면 SettingsActivity화면으로 넘어가도록 할 수 있습니다.


아직 SettingsActivity는 빈화면이니까 이 화면을 구현할 차례입니다.


일단 화면의 Layout을 잡아줍니다.


그러려면 res에 xml폴더를 생성해서 아래와 같이 pref_general.xml을 만듭니다.



한개의 EditTextPreference와 한개의 ListPreference를 만들었습니다.


참고로 strings.xml에는 아래와 같은 내용들이 있습니다.


  <!-- Label for the location preference [CHAR LIMIT=30] -->
    <string name="pref_location_label">Location</string>

    <!-- Key name for storing location in SharedPreferences [CHAR LIMIT=NONE] -->
    <string name="pref_location_key" translatable="false">location</string>

    <!-- Default postal code for location preference [CHAR LIMIT=NONE] -->
    <string name="pref_location_default" translatable="false">55347</string>

    <!-- Label for the temperature units preference [CHAR LIMIT=30] -->
    <string name="pref_units_label">Temperature Units</string>

    <!-- Label for metric option in temperature unit preference [CHAR LIMIT=25] -->
    <string name="pref_units_label_metric">Imperial</string>

    <!-- Label for imperial option in temperature unit preference [CHAR LIMIT=25] -->
    <string name="pref_units_label_imperial">Imperial</string>

    <!-- Key name for temperature unit preference in SharedPreferences [CHAR LIMIT=NONE] -->
    <string name="pref_units_key" translatable="false">units</string>

    <!-- Value in SharedPreferences for metric temperature unit option [CHAR LIMIT=NONE] -->
    <string name="pref_units_metric" translatable="false">metric</string>

    <!-- Value in SharedPreferences for imperial temperature unit option [CHAR LIMIT=NONE] -->
    <string name="pref_units_imperial" translatable="false">imperial</string>



SettingsActivity에 보시면 addPreferencesFromResource(R.xml.pref_general); 이있습니다.

방금 만든 pref_general을 불러오는 부분이죠.


그리고 나서 아래와 같이 리스너를 물려 줍니다.

        bindPreferenceSummaryToValue(findPreference(getString(R.string.pref_location_key)));
        bindPreferenceSummaryToValue(findPreference(getString(R.string.pref_units_key)));


이미 위 SettingsActivity에서 다 구현해 놨던 겁니다.



여기서 사용자가 우편번호를 입력하면 그 값은 자동으로 SharedPreference에 저장이 됩니다.

그래서 날씨를 표시할 때 사용자가 입력한 우편번호를 SharedPreference에서 가져와서 그 지역 날씨를 표시하게 되죠.

만약 사용자가 입력한 우편번호가 없다면 저 strings.xml에 있는 default값인 55347을 사용하게 됩니다.


이것은 ForecastFragment에 있는 onOptionsItemSelected() 를 아래와 같이 코딩하면 구현할 수 있습니다.


    @Override
    public boolean onOptionsItemSelected(MenuItem item) {
        // Handle action bar item clicks here. The action bar will
        // automatically handle clicks on the Home/Up button, so long
        // as you specify a parent activity in AndroidManifest.xml.
        int id = item.getItemId();
        if (id == R.id.action_refresh) {
            updateWeather();
            return true;
        }
        return super.onOptionsItemSelected(item);
    }


옵현 아이템이 선택되면 그 ID 가 refresh 이면 updateWeather()를 돌리도록 합니다.


    private void updateWeather() {
        FetchWeatherTask weatherTask = new FetchWeatherTask();
        SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(getActivity());
        String location = prefs.getString(getString(R.string.pref_location_key),
                getString(R.string.pref_location_default));
        weatherTask.execute(location);
    }


updateWeather에서는 location 값을 받아서 weatherTask.execute()에 넘겨 줍니다.


이 weatherTask는 이전에 구현해 놓은 FetchWeatherTask로 웹사이트에 날씨를 요청하고 받아서 이를 뿌려주도록 합니다.


참고로 ForecaseFragment 클래스의 onStart()를 아래와 같이 구현합니다.


    @Override
    public void onStart() {
        super.onStart();
        updateWeather();
    }


그러면 앱이 처음 실행할 때도 디폴트 값을 가져와서 그 지역의 날씨를 표시하게 됩니다.


이제 섭씨/화씨를 선택하는 부분을 볼건데요.


위에 소스코드에도 있듯이 여기서는 ListPreference를 사용할 겁니다.


참고로 imperial은 화씨를 말하고 metric은 섭씨를 말합니다.


T



emperature Units  부분은 stings.xml을 변경하는 과정에서 실수가 있어서 Imperial만 뜨네요.

다시 strings.xml을 수정해야 겠습니다.


일단 Settings 와 관련 된 부분은 모두 마쳤습니다.


여기까지의 소스코드는 아래에서 받을 수 있습니다.

https://github.com/udacity/Sunshine-Version-2/tree/3.11_add_units_setting




반응형

Comment

  1. 익명 2016.10.12 00:09

    비밀댓글입니다