블로그 이미지
미국에서 모바일 애플리케이션을 개발하고 있습니다. 요즘 Corona로 앱을 하나 개발하고 있는데 나도 공부 하면서 여러 분들에게 소개도 하고 싶어서 블로그를 만들었습니다.
솔웅

최근에 받은 트랙백

글 보관함

calendar

        1 2 3
4 5 6 7 8 9 10
11 12 13 14 15 16 17
18 19 20 21 22 23 24
25 26 27 28 29 30  

[Android] Settings - 1 -

2016.09.25 12:39 | Posted by 솔웅


Settings

앱에는 사용자가 기능 선택을 할 수 있는 세팅 메뉴를 가지고 있는 경우가 많다. 예를 들어 어떤 앱은 notification 가능 여부를 사용자가 선택할 수 있도록 하기도 하고 클라우드에 동기화 되는 주가 등을 설정하도록 하기도 합니다.
이 세팅 메뉴를 넣으려면 안드로이드의 Preference API를 사용해서 만들어야 합니다.

Setting Design


세팅을 어떤 모양으로 개발하느냐 하는 것은 Settings design guide를 살펴 보세요.





Figure 1. Screenshots from the Android Messaging app's settings. Selecting an item defined by a Preference opens an interface to change the setting.


안드로이드의 메세지 앱의 세팅 화면 입니다. 아이템을 누르면 지정된 Preference 의 세팅 화면이 열립니다.



Overview



User Interface를 위해 View object를 사용하는 대신 Settings는 XML 파일에 정의하도록 하는 이미 만들어진 Preference 클래스의 여러가지 subclass 등을 사용해서 표현 합니다.
Preference 객체는 한개의 세팅에 대한 building block 입니다. 각각의 Preference는 리스의 한 아이템으로 나타나고 사용자에게 해당 UI를 제공해 사용자가 setting을 modify 할 수 있도록 합니다.
예를 들어 CheckBoxPreference 는 체크박스를 표시하는 리스트 아이템을 생성합니다. 그리고 ListPreference는 여러개 중에 하나를 선택할 수 있는 리스트와 함께 dialog를 여는 아이템을 만듭니다.

Preference는 key-value 의 쌍으로 이뤄져 있고 이를 default SharedPreference file에 세팅된 내용을 저장하도록 합니다.
사용자가 세팅을 바꾸면 시스템은 이 SharedPreference 파일의 해당 내용을 업데이트 합니다. 이 SharedPreferences 파일을 직접 접근해서 다루는 것은 세팅된 내용을 read 해야 할 때 입니다.

각 세팅에 대해 SharedPreferences에 저장된 값들은 아래 data type들로 이뤄져 있습니다.

    Boolean
    Float
    Int
    Long
    String
    String Set

여러분 앱의 세팅 UI는 Preference 객체를 사용해 만들어 졌기 때문에 (View 객체가 아니라) 특별한 Activity나 Fragment subclass를 사용해서 이 리스트 세팅을 표시해야 합니다.

- 안드로이드 버전 3.0 미만 (API level 10 미만) 에서는 액티비티를 반드시 PreferenceActivity 클래스의 extension으로 build 해야 합니다.
- 안드로이드 버전 3.0 이상 에서는 PreferenceFragment를 가지고 있는 traditional Activity를 사용해서 앱 세팅을 표시해야 합니다. 여러 그룹의 세팅이 있다면 큰 화면을 둘로 나눠 이를 표시하기 위해 PreferenceActivity를 사용할 수도 있습니다.

어떻게 PreferenceActivityPreferenceFragment를 세팅하느냐 하는것은 Creating a Preference Activity Using Preference Fragment 에 대해 설명할 때 다를 겁니다.



Preference



앱에서 사용되는 세팅은 Preference 클래스의 subclass 를 사용해서 표현합니다. 각각의 sub 클래스는 property들의 세트로 이뤄져 있어 세팅의 타이틀과 디폴트값 같은 것들을 특정할 수 있도록 합니다.
각각의 subclass는 각자 자신들의 특징을 나타내는 프로퍼티와 인터페이스들을 제공합니다. 예를 들어 figure 1은 메세징 앱의 세팅에서 화면을 캡쳐한 것입니다 세팅 화면에 있는 각 리스트 아이템은 각기 다른 Preference 객체들을 지원하고 있습니다.

일반적으로 사용하는 preference들 몇개를 보면

 
CheckBoxPreference
    Shows an item with a checkbox for a setting that is either enabled or disabled. The saved value is a boolean (true if it's checked).


ListPreference
    Opens a dialog with a list of radio buttons. The saved value can be any one of the supported value types (listed above).


EditTextPreference
    Opens a dialog with an EditText widget. The saved value is a String.
   
   
다른 subclass들과 거기에 속하는 프로퍼티들을 보시려면 Preference 클래스를 참조하세요.

물론 이렇게 제공되는 클래스들이 모든것들을 커버하지는 못합니다. 어떤 경우에는 다른 특정한 형태가 필요할 수 있습니다. 예를 들어 숫자나 날짜를 picking 하는 preference 클래스는 제공되지 않습니다. 그래서 여러분만의 Preference Subclass를 만들어야 될 수도 있습니다. 이것에 대해 알고 싶으시면 Building a Custom Preference 섹션을 보세요.



Defining Preferences in XML



runtime에 Preference object를 instantiate 할수도 있지만 세팅 리스트는 XML에 Preference objects 의 hierarchy 와 함께 정의 해 놔야 합니다.
settings의 collection을 정의하기 위해 XML 파일을 사용하는 것이 더 좋습니다. 왜냐하면 이렇게 하면 쉽게 읽을 수 있고 update 하기도 간단하기 때문이죠.
또한 세팅은 일반적으로 pre-determined 됩니다. 그리고 runtime 때 이 collection들을 수정할 수도 있습니다.

Preference subclass는 클래스 이름을 사용해서 XML element로 정의 될 수 있습니다. i.e. <CheckBoxPreference>
이 XML 파일은 res/xml 디렉토리에 저장해야만 합니다. 파일 이름은 마음대로 해도 되지만 일반적으로 preferences.xml 로 합니다.
대개 1개의 파일만 필요합니다. 왜냐하면 hierarchy의 branch 들은 PreferenceScreen 대신 nested instance들에 의해 정의되기 때문입니다.

Note : 세팅에 multi-pane layout을 만드려면 각 fragment당 별도의 XML 파일을 말들어야 합니다.

XML 파일의 root node는 반드시 element 여야 합니다. 이 element 안에 각각의 Preference를 추가 합니다. <PreferenceScreen> element 안에 추가한 각 child는 세팅 리스트안의 각 아이템으로 표시됩니다.




예제



<?xml version="1.0" encoding="utf-8"?>
<PreferenceScreen xmlns:android="http://schemas.android.com/apk/res/android">
    <CheckBoxPreference
        android:key="pref_sync"
        android:title="@string/pref_sync"
        android:summary="@string/pref_sync_summ"
        android:defaultValue="true" />
    <ListPreference
        android:dependency="pref_sync"
        android:key="pref_syncConnectionType"
        android:title="@string/pref_syncConnectionType"
        android:dialogTitle="@string/pref_syncConnectionType"
        android:entries="@array/pref_syncConnectionTypes_entries"
        android:entryValues="@array/pref_syncConnectionTypes_values"
        android:defaultValue="@string/pref_syncConnectionTypes_default" />
</PreferenceScreen>




이 예제에서는 CheckBoxPreference ListPreference 가 있습니다. 각 아이템들은 아래의 3가지 attribute들을 포함하고 있습니다.


android:key
    This attribute is required for preferences that persist a data value. It specifies the unique key (a string) the system uses when saving this setting's value in the SharedPreferences.

    The only instances in which this attribute is not required is when the preference is a PreferenceCategory or PreferenceScreen, or the preference specifies an Intent to invoke (with an <intent> element) or a Fragment to display (with an android:fragment attribute).


android:title
    This provides a user-visible name for the setting.


android:defaultValue
    This specifies the initial value that the system should set in the SharedPreferences file. You should supply a default value for all settings.
   
attribute에 대한 정보를 얻으려면 Preference (and respective subclass) 문서를 참조하세요.

세팅 리스트가 10 아이템을 초과하면 세팅의 그룹별로 title을 추가하고 싶을 겁니다. 혹은 그룹을 별도의 화면에 포시하던가요. 이러한 기능은 아래 섹션을 보세요.



Creating Setting Groups




Figure 2. Setting categories with titles.
1. The category is specified by the <PreferenceCategory> element.
2. The title is specified with the android:title attribute.



10개 이상의 세팅 리스트가 있으면 사용자가 보기 어려워 질 겁니다. 이럴 경우 세팅 리스트를 그룹화 시키면 도움이 될 겁니다. 이렇게 세팅을 그룹화 시키려면 아래 두가지 방법 중 하나를 사용하시면 됩니다.

   
    Using titles
    Using subscreens

이 중 하나만 사용해도 되고 둘 다 사용해도 됩니다. 어떤 걸 사용할 것인지는 어떻게 구분할 지에 따라 결정됩니다. 자세한 것은 Android Design's Settings guide를 참조하세요.



Using titles



세팅내 그룹들 사이에 divider와 heading을 제공하려면 (figure 2) PreferenceCategory 안에 Preference 객체들을 각 그룹으로 묶어 놓습니다.



<PreferenceScreen xmlns:android="http://schemas.android.com/apk/res/android">
    <PreferenceCategory
        android:title="@string/pref_sms_storage_title"
        android:key="pref_key_storage_settings">
        <CheckBoxPreference
            android:key="pref_key_auto_delete"
            android:summary="@string/pref_summary_auto_delete"
            android:title="@string/pref_title_auto_delete"
            android:defaultValue="false"... />
        <Preference
            android:key="pref_key_sms_delete_limit"
            android:dependency="pref_key_auto_delete"
            android:summary="@string/pref_summary_delete_limit"
            android:title="@string/pref_title_sms_delete"... />
        <Preference
            android:key="pref_key_mms_delete_limit"
            android:dependency="pref_key_auto_delete"
            android:summary="@string/pref_summary_delete_limit"
            android:title="@string/pref_title_mms_delete" ... />
    </PreferenceCategory>
    ...
</PreferenceScreen>




Using subscreens



subscreen으로 세팅 그룹을 나누고 싶으면 (figure 3) PreferenceScreen 안에 Preference 객체들의 그룹을 묶어 놓습니다.



Figure 3. Setting subscreens. The <PreferenceScreen> element creates an item that, when selected, opens a separate list to display the nested settings.



예제



<PreferenceScreen  xmlns:android="http://schemas.android.com/apk/res/android">
    <!-- opens a subscreen of settings -->
    <PreferenceScreen
        android:key="button_voicemail_category_key"
        android:title="@string/voicemail"
        android:persistent="false">
        <ListPreference
            android:key="button_voicemail_provider_key"
            android:title="@string/voicemail_provider" ... />
        <!-- opens another nested subscreen -->
        <PreferenceScreen
            android:key="button_voicemail_setting_key"
            android:title="@string/voicemail_settings"
            android:persistent="false">
            ...
        </PreferenceScreen>
        <RingtonePreference
            android:key="button_voicemail_ringtone_key"
            android:title="@string/voicemail_ringtone_title"
            android:ringtoneType="notification" ... />
        ...
    </PreferenceScreen>
    ...
</PreferenceScreen>




Using intents



어떤 경우는 preference item을 settings screen이 아니라 다른 activity에서 열기를 원할 때도 있을 수 있습니다.
예를 들어 웹페이지를 보기 위한 웹브라우저 같은 경우.
사용자가 preference item을 선택했을 때 Intent 를 invoke 하려면 <intent> element를 해당 <preference> element의 child로 추가 합니다.

예를 들어 웹 페이지를 열 경우 이렇게 합니다.



<Preference android:title="@string/prefs_web_page" >
    <intent android:action="android.intent.action.VIEW"
            android:data="http://www.example.com" />
</Preference>



다음의 attribute들을 사용해서 implicit/explicit intent를 사용할 수 있습니다.


android:action
    The action to assign, as per the setAction() method.


android:data
    The data to assign, as per the setData() method.


android:mimeType
    The MIME type to assign, as per the setType() method.


android:targetClass
    The class part of the component name, as per the setComponent() method.


android:targetPackage
    The package part of the component name, as per the setComponent() method.

   
Creating a Preference Activity



settings를 activity 안에 표시하려면 PreferenceActivity class를 extend 합니다.
Preference objects 의 hierarchy에 기반해 settings 리스트를 표시하는 Activity class의 extension 입니다.
PreferenceActivity는 사용자가 변경을 했을 때 각 preference와 연관된 세팅들을 자동적으로 persist 시켜 줍니다.

Note : Android 3.0 이상이면 대신에 PreferenceFragment를 사용해야 합니다. 사용법은 Using Preference Fragments section에서 설명 됩니다.



기억해야 할 가장 중요한 부분은 onCreate() callback 동안 view들의 레이아웃을 로딩하지 않는다는 겁니다. 대신에 addPreferencesFromResource() 를 호출해서 XML 파일에 선언한 preference를 Activity에 추가하게 됩니다.
예를 들어 PreferenceActivity를 위한 아주 간단한 코드는 아래와 같습니다.



public class SettingsActivity extends PreferenceActivity {
    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        addPreferencesFromResource(R.xml.preferences);
    }
}



이 정도면 어떤 경우에는 충분할 겁니다. 왜냐하면 사용자가 preference를 수정하면 시스템은 이 변경된 값을 default SharedPreferences 파일에 저장을 할 것이기 때문입ㅂ니다.
이렇게 되면 다른 어플리케이션 컴포넌트들에서 이 사용자의 세팅값을 읽어서 사용할 수 있게 됩니다.
하지만 대부분의 경우에는 좀 더 코딩이 필요할 겁니다. 변경이 될 떄 listen 하기 위한 경우 일 텐데요. 이와 관련해서는 Reading Preferences section을 참조하세요.



Using Preference Fragments



Android 3.0 (API level11) 이상에서는 Preference objects의 리스트를 표시하기 위해 PreferenceFragment를 사용해야 합니다.
어느 activity에나 이 PreferenceFragment를 추가할 수 있습니다. (PreferenceActivity를 사용할 필요가 없습니다.)

onCreate() 메소드에서 addPreferencesFromResource() 를 사용하면 아주 간단하게 PreferenceFragment를 implement 할 수 있습니다.



예제



public static class SettingsFragment extends PreferenceFragment {
    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);

        // Load the preferences from an XML resource
        addPreferencesFromResource(R.xml.preferences);
    }
    ...
}



이렇게 한 후 이 fragment를 Activity에 추가하려면 다른 Fragment를 추가하는 것과 똑 같이 하시면 됩니다.




예제



public class SettingsActivity extends Activity {
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);

        // Display the fragment as the main content.
        getFragmentManager().beginTransaction()
                .replace(android.R.id.content, new SettingsFragment())
                .commit();
    }
}



Note : PreferenceFragment는 Context object를 가지고 있지 않습니다. 만약에 Context 객체가 필요하면 getActivity()를 call 하실 수 있습니다.
이 경우 주의해야 할 사항은 activity에 fragment가 attach됐을 때 사용해야 한다는 겁니다. attach 되지 않았을 경우나 lifecycle이 종료되서 detached 됐을 경우 getActivity() 는 null을 return 하게 됩니다.



Setting Default Values



생성된 preferences들은 앱에서 중요한 behavior들이 정의 돼 있을 겁니다. 그래서 관련된 SharedPreferences 파일을 default value들과 함께 initialize 시키는 것이 중요합니다.
이 작업은 사용자가 앱을 처음 open 할 떄 이뤄져야 합니다.

이를 위해 첫번째로 해야 할 것은 XML 파일에 각 Preference objects 마다 default value를 정해줘야 한다는 겁니다. 이 경우 android:defaultValue attribute를 사용합니다.
이 값은 어떤 data type도 될 수 있습니다.



예제



<!-- default value is a boolean -->
<CheckBoxPreference
    android:defaultValue="true"
    ... />

<!-- default value is a string -->
<ListPreference
    android:defaultValue="@string/pref_syncConnectionTypes_default"
    ... />

그런 다음 main activity의 onCreate() 메소드에서 setDefaultValues();를 호출합니다.



PreferenceManager.setDefaultValues(this, R.xml.advanced_preferences, false);



onCreate()에서 호출 할 때 앱에는 디폴트 세팅이 제대로 초기화 되어 있어야 합니다. 예를 들어 cellular network 에서 다운로드를 할 것인지 여부 같은 것들이 제대로 세팅 되어 있어야 할 겁니다.



이 메소드는 세개의 arguments를 가지고 있습니다.



    Your application Context.
    The resource ID for the preference XML file for which you want to set the default values.
    A boolean indicating whether the default values should be set more than once.


    false일 경우 시스템은 이 메소드가 이전에 한번도 호출되지 않았을 경우에만 디폴트 값들을 세팅합니다. (or the KEY_HAS_SET_DEFAULT_VALUES in the default value shared preferences file is false).

3번째 argument를 false로 세팅하면 사용자가 저장한 preference를 디폴트 값으로 overriding 하지 않고 reseting 함으로서 activity가 시작될 때마다 안전하게 호출하도록 할 수 있습니다.
이 값을 true로 설정하면 이전의 저장된 값이 디폴트 값으로 override 하게 됩니다.

저작자 표시 비영리 동일 조건 변경 허락
신고


요즘 대체에너지에 관심이 많이 가서 직접 사용해 보기로 했습니다.
그래서 일단 휴대용 태양광 발전기를 수소문 하다가 Goal Zero사의 제품을 구입했습니다.




GOAL ZERO YETI 150 Solar Generator 와 NOMAD 20 Solar Panel 입니다.


원래 가격은 Generator가 229.99 달러이고 태양광 패널은 199.99 달러 입니다.
그런데 여기저기 구글링 하다가 온라인 쇼핑몰에서 조금 더 싸게 샀습니다.

제너레이터는 Bed Bath & Beyond에서 159.99 달러에 샀습니다.
Tax 11.64 달러 붙어서 171.63 달러가 지출 했어요.

그리고 패널은 140.48달러에 샀습니다. 세금은 없었습니다.

그래서 총 312.11 불 들었습니다.


한 일주일간 사용해 본 후기는....

충전 시간이 너무 길다.....




제품설명서에 보면 구입한 Solar Panel로 충전을 하려면 엥꼬에서 만땅 채우는데 무려 17~34시간이 걸린 답니다.
그것도 아주 햇볕 조건이 좋을 때....

하루 종일 해가 떠 있는 것도 아니고.. 하루 8시간으로 계산해도 4일정도는 걸리는데...
그것도 아침 저녁으로는 해가 약하고 또 날씨가 흐리거나 비가 오면 충전 속도가 느리니까...
태양광 패널로 Full Charge 하려면 10일은 걸리겠네요.

가정용 전기로 충전해도 되지만 (이럴 경우 8시간 걸림) 태양광 발전을 직접 체험해 보기 위해 산거니까 패널로만 계속 충전해 보려구요.

이번주는 날씨가 계속 흐렸거든요.
차 운전석 앞에 패널을 놓고 일주일 내내 남쪽을 향해 주차를 해 놓고 있었는데...
계속 40% 에서 60% 로 가는 눈금만 깜빡입니다.

밧데리 눈금이 올라가지 않아요.

다행히 다음주엔 해 쩅쩅인 날이 많은것 같아서 기대하고 있습니다.




과연 만땅을 채울 수 있을 지......


용도는 자동차로 돌아다니거나 여행 다닐 때 모바일 기기 충전용으로 좋은 것 같습니다.
자동차 12 볼트 어댑터에서 충전할 수도 있지만..
거긴 네비게이션이 꽃혀있어야 해서 모바일 기기랑 서로 번갈아 가며 충전을 했었는데 좀 불편하더라구요.
더군다나 가족도 핸드폰이 있어서 그거 하나로는 많이 부족했는데...

일단 이 제너레이터와 태양광 패널은 크기가 작아 차에 놓고 다니기 편해서 유용하게 사용할 수 있습니다.

태양광 발전으로 충전을 하려면 Solar Panel, Charge Controller, Inverter, Battery 이렇게 4가지가 기본적으로 필요한데.
이 제너레이터에는 Charge Controller, Inverter 그리고 Battery가 하나의 통속에 들어있어 따로 구입해서 연결하는 작업을 할 필요가 없습니다.
그래서 따로 구입하는 것 보다 공간도 덜 차지하고 각각 구입하는 것보다 가격도 저렴하게 구입할 수 있습니다.

저는 그냥 자동차에 항상 배치해 놓고 있습니다. 집안으로 들여놨다가 다시 차로 가져가고 하는 것도 일이더라구요.
더군다나 다른 짐들도 있고...

30여만원 주고 샀으니 단지 핸드폰 충전용으로는 좀 비싸긴 하지만 대체 에너지에 대해 체험하고 배우는 과정으로 생각하면서 위안을 삼고 있어요.

다음엔 인력을 이용해 발전을 할 수 있는 장난감을 만들어 볼 생각입니다.
그리고 풍력발전도 체험해 보고 싶고...

그런거 만들려면 여러가지 Tool들이 필요하겠더라구요.
그래서 요즘 열심히 Garage Sale 을 돌아다니고 있습니다. :)



저작자 표시 비영리 동일 조건 변경 허락
신고


3과에서는 날씨 리스트에서 한 라인을 클릭하면 그 날의 자세한 날씨가 표시되도록 할 겁니다.
클릭하면 다른 화면으로 넘어가는데요. 이것은 또 다른 Activity를 생성하고 Main Activity 에서 이 새로운 Activity로 전환할 수 있는 기능이 필요합니다.
그리고 새로운 화면 (Activity)로 넘어간 후 그곳에서 표시해 줄 정보를 출력해서 보여주는 UI를 만드는 일도 해야 하구요.

대충 이런 기능들을 구현할 것 같습니다.

리스트에서 아이템을 클릭했을 경우 작동하는 메소드는 setOnItemClickListener 입니다.
https://developer.android.com/reference/android/widget/ListView.html

이 메소드를 기존 코드에서 구현할 겁니다.

ForecastFragment class의 onCreateView 로 가서 맨 아래에 아래와 같이 코드를 추가합니다.



       // Get a reference to the ListView, and attach this adapter to it.
        ListView listView = (ListView) rootView.findViewById(R.id.listview_forecast);
        listView.setAdapter(mForecastAdapter);
        listView.setOnItemClickListener(new AdapterView.OnItemClickListener() {

            @Override
            public void onItemClick(AdapterView<?> adapterView, View view, int position, long l) {
                String forecast = mForecastAdapter.getItem(position);
                Toast.makeText(getActivity(), forecast, Toast.LENGTH_SHORT).show();
            }


listView.setAdapter(mForecastAdapter); 까지는 이전에 있었습니다.

그 이후에 setOnItemClickListener() 를 구현했는데요.

이 메소드 안의 onItemClick()을 Override 했습니다.


이 안에서는 클릭한 아이템의 포지션을 Toast로 보이도록 했습니다.



이렇게 하면 위에 보이는 것처럼 아이템을 클릭했을 시 그 아이템 내용이 Toast에 잠깐 보였다가 사라집니다.


이렇게 되면 onItemClick 까지 제대로 잘 작동 되고 있는 것을 알 수 있습니다.



이 다음에는 클릭한 날의 자세한 날씨를 보여주는 새로운 페이지로 이동해야 합니다.


그러려면 이동할 페이지를 만들어야 하고 이 새로운 페이지를 AndroidManifest파일에 등록해야 합니다.


이 새로운 페이지에서는 이전 화면으로 돌아가는 버튼을 만들겁니다.

그리고 그 아래에 해당 날짜의 자세한 정보를 보여 줄것이구요.


우선 DetailActivity를 생성합니다.


New-Activity-Blank Activity 를 선택합니다.



Activity 이름은 DetailActivity로 하고 Hierarchical Parent는 MainActivity로 합니다.

그리고 Use a Fragment도 선택을 합니다.



그러면 DetailActivity클래스와 함께 DetailActivityFragment 클래스가 자동으로 생성됩니다.

그리고 관련된 xml파일들도 생성됩니다. (activity_detail.xml, fragment_detail.xml)


일단 DetailActivity는 이렇게 만듭니다.



/*
 * Copyright (C) 2014 The Android Open Source Project
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package com.example.android.sunshine.app;

import android.os.Bundle;
import android.support.v4.app.Fragment;
import android.support.v7.app.ActionBarActivity;
import android.view.LayoutInflater;
import android.view.Menu;
import android.view.MenuItem;
import android.view.View;
import android.view.ViewGroup;

public class DetailActivity extends ActionBarActivity {

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_detail);
        if (savedInstanceState == null) {
            getSupportFragmentManager().beginTransaction()
                    .add(R.id.container, new PlaceholderFragment())
                    .commit();
        }
    }


    @Override
    public boolean onCreateOptionsMenu(Menu menu) {
        // Inflate the menu; this adds items to the action bar if it is present.
        getMenuInflater().inflate(R.menu.detail, menu);
        return true;
    }

    @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) {
            return true;
        }

        return super.onOptionsItemSelected(item);
    }

    /**
     * A placeholder fragment containing a simple view.
     */
    public static class PlaceholderFragment extends Fragment {

        public PlaceholderFragment() {
        }

        @Override
        public View onCreateView(LayoutInflater inflater, ViewGroup container,
                                 Bundle savedInstanceState) {

            View rootView = inflater.inflate(R.layout.fragment_detail, container, false);
            return rootView;
        }
    }
}


그리고 activity_detail.xml은 이렇게 합니다.


<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools" android:id="@+id/container"
    android:layout_width="match_parent" android:layout_height="match_parent"
    tools:context="com.example.android.sunshine.app.DetailActivity" tools:ignore="MergeRootFrame" />


그리고 menu_detail.xml은 detail.xml로 이름을 바꿉니다.

해당 xml에서 오른쪽 마우스 클릭을 한 후 Refactor - Rename을 선택하면 이름을 바꿀 수 있습니다.



그리고 DetailActivityFragment.java는 delete합니다.

이건 현재 DetailActivity.java에 있는 PlaceholderFragment.java로 replace될 겁니다.


이렇게 된 코드는 3.02_create_detail_activity  에서 받아 볼 수 있습니다.





Activity들 간에 이동을 하려면 startActivity(Intent)를 사용하면 됩니다.


위에서 Toast를 구현했던 부분에 이 startActivity()를 구현할 겁니다.


setOnItemClick()을 아래와 같이 바꿉니다.


        listView.setOnItemClickListener(new AdapterView.OnItemClickListener() {

            @Override
            public void onItemClick(AdapterView<?> adapterView, View view, int position, long l) {
                String forecast = mForecastAdapter.getItem(position);
                //Toast.makeText(getActivity(), forecast, Toast.LENGTH_LONG).show();

Intent intent = new Intent(getActivity(), DetailActivity.class).putExtra(Intent.EXTRA_TEXT, forcast);

startActivity(intent)

            } 


이렇게 하면 DetailActivity 클래스로 이동합니다.


현재 상태에서는 DetailActivity로 넘어가면 아무것도 안 보일 겁니다.


fragment_detail.xml 에 있는 내용이 뿌려질건데 현재 그 내용은 아래와 같습니다.


<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools" android:layout_width="match_parent"
    android:layout_height="match_parent" android:paddingLeft="@dimen/activity_horizontal_margin"
    android:paddingRight="@dimen/activity_horizontal_margin"
    android:paddingTop="@dimen/activity_vertical_margin"
    android:paddingBottom="@dimen/activity_vertical_margin"
    tools:context="com.example.android.sunshine.app.DetailActivityFragment">


</RelativeLayout>


아무것도 내용이 없습니다.


여기에 해당 날짜의 forcast data를 읽어서 뿌려 주도록 하겠습니다.


DetailActivity의 onCreateView() 안에 아래와 같이 코등합니다.


        @Override
        public View onCreateView(LayoutInflater inflater, ViewGroup container,
                                 Bundle savedInstanceState) {

            View rootView = inflater.inflate(R.layout.fragment_detail, container, false);

            // The detail Activity called via intent.  Inspect the intent for forecast data.
            Intent intent = getActivity().getIntent();
            if (intent != null && intent.hasExtra(Intent.EXTRA_TEXT)) {
                String forecastStr = intent.getStringExtra(Intent.EXTRA_TEXT);
                ((TextView) rootView.findViewById(R.id.detail_text))
                        .setText(forecastStr);
            }

            return rootView;
        }


그리고 fragment_detail.xml은 아래와 같이 합니다.


<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools" android:layout_width="match_parent"
    android:layout_height="match_parent" android:paddingLeft="@dimen/activity_horizontal_margin"
    android:paddingRight="@dimen/activity_horizontal_margin"
    android:paddingTop="@dimen/activity_vertical_margin"
    android:paddingBottom="@dimen/activity_vertical_margin"
    tools:context="com.example.android.sunshine.app.DetailActivity.DetailFragment">

    <TextView android:text="@string/hello_world" android:layout_width="wrap_content"
        android:id="@+id/detail_text"
        android:layout_height="wrap_content" />

</RelativeLayout>


이제 리스트 아이템을 클릭하면 Toast가 나오는 대신 아래와 같이 DetailActivity가 표시 될 겁니다.




여기까지 진행된 소스코드는 이곳에서 받으실 수 있습니다.


https://github.com/udacity/Sunshine-Version-2/tree/3.04_populate_detail_text




이제 DetailActivity에 해당 날짜의 자세한 날씨를 표시하는 화면을 구성할 차례입니다.


이 작업은 다음 글에서 이어 나가겠습니다.




저작자 표시 비영리 동일 조건 변경 허락
신고
이전 1 2 3 4 5 ... 293 다음

티스토리 툴바