이번엔 Settings 를 꾸밀 겁니다.
Setting 관련 한 Android Developer API Guide는 여기에 있습니다.
이 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
'WEB_APP > Android' 카테고리의 다른 글
[Android] Optional SQLite Tutorial (0) | 2016.10.23 |
---|---|
Udacity 강좌 - Lesson 4 - Activity (0) | 2016.10.23 |
[Android] Settings - 3 - (0) | 2016.10.13 |
[Android] Settings - 2 - (0) | 2016.10.10 |
Udacity 강좌 - Lesson 3 실습 03 - Implicit Intent - (0) | 2016.10.09 |
[Android] Settings - 1 - (0) | 2016.09.26 |
Udacity 강좌 - Lesson 3 실습 01 - 다른 Activity로 화면 전환하기 - (0) | 2016.09.21 |
Android Toast 정리 (0) | 2016.09.07 |
Udacity 강좌 - Lesson 2 소스 실행 순서 따라가기 (0) | 2016.09.06 |
Udacity 강좌 - Lesson 2 실습 05 (2) | 2016.08.29 |