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

최근에 받은 트랙백

글 보관함

[CookBook] Fragments 이해하기 -10-

2013. 10. 1. 20:08 | Posted by 솔웅


Setting user's Preferences with PreferenceFragment


PreferenceFragment는 유저가 어플리케이션을 configure하고 personalize할 수 있도록 하는 fragment 입니다. 이 PreferenceFragment는 여러개의 preference view들을 가질 수 있습니다. 애플리케이션의 preference를 쉽게 세팅할 수 있도록 도와주기 위해서이죠. PreferenceFragments에는 아래와 같은 preference view 들이 있습니다.



PreferenceScreen : preference screen을 정의하기 위해 사용되는 XML의 root element.

CheckBoxPreference : check되면 true를 안되면 false를 return 하는 간단한 check box를 표시한다.

ListPreference : 사용자가 선택할 수 있는 radio button들의 리스트를 표시한다.

EditTextPreference : 사용자가 텍스트를 입력할 수 있는 EditText dialog를 표시한다.

RingtonePreference : ringtone을 가리키는 radio button을 표시한다.

PreferenceCategory : 카테고리 내의 관계된 preference들을 grouping 한다.

Preference : Button 처럼 사용하는 custom preference



어떻게 어플리케이션 preference들이 세팅되는지 이해하기 위해 PrefFragmentApp이라는 안드로이드 프로젝트를 일단 만들어 보죠. pPreferenceFragment에서 preference view들을 표시하는 방법에는 두가지가 있습니다. XML 파일을 이용하는 방법과 code를 이용하는 방법이 있습니다. 우리는 XML을 이용하는 방법을 시도해 보겠습니다. 그러니까 먼저 res 폴더 밑에 xml 이라는 폴더를 먼저 만드셔야 합니다. 이 res/xml 이라는 폴더 밑에 preference.xml 이라는 XML 파일을 추가하시면 됩니다. 이 xml 에는 어플리케이션의 configure를 위해 유저에게 표시될 preference view들이 선언돼 있습니다. 이 preference view들 중 유저가 선택한 옵션들은 어플리케이션 내에 계속 유지될 겁니다.






preference.xml



<?xml version="1.0" encoding="utf-8"?>
<PreferenceScreen xmlns:android="http://schemas.android.com/apk/res/android" >
    <PreferenceCategory android:title="Category 1">
        <CheckBoxPreference
            android:title="Newsletter"
            android:defaultValue="false"
            android:key="Newskey"  />
        <EditTextPreference android:key="Namekey"
            android:title="Enter your name: "
            android:dialogTitle="Enter your name" >
        </EditTextPreference>
    </PreferenceCategory>
    <PreferenceCategory android:title="Category 2">
        <RingtonePreference android:showDefault="true"
            android:key="Audio" android:title="Select sound"
            android:ringtoneType="notification" >
        </RingtonePreference>
        <ListPreference android:title="Products List "
            android:key="products_list"
            android:entries="@array/products"
            android:entryValues="@array/prodselected"
            android:dialogTitle="Choose a product" >
        </ListPreference>
    </PreferenceCategory>
    <Preference
        android:title="Submit"
        android:key="submitPref" />
</PreferenceScreen>



이 PreferenceScreen 안에는 두개의 PreferenceCategory가 있는게 보이실 겁니다. Category 1에는 CheckboxPreference, EditTextPreference 이렇게 두개의 preference view가 있습니다. Category 2에는 RingtonePreference, ListPreference 이렇게 있구요. 모든 preference view는 android:key 값을 가져야 합니다. 일정의 id이죠. android:title 속성은 preference view의 초기값을 할당하기 위해 사용됩니다. 그리고 android:defaultValue 속성은 preference view에 디폴트 값을 할당할 때 사용되구요.



CheckBoxPreference는 UI element로서 check box를 표시합니다. 여기에는 Boolean 형식으로 값이 저장되구요. 체크박스가 선택되면 true값이 선택되지 않으면 false 값이 저장됩니다.  android:default 속성을 사용해서 디폴트 값을 false로 설정했습니다.



EditTextPreference 는 android:key 속성에 Namekey 라고 정해져 있습니다. 그리고 android:title에는 Enter your name : 이 지정돼 있구요. 이 EditTextPreference 가 선택되면 title이 Enter your name 이라는 dialog가 뜰 겁니다. 사용자가 정보를 입력하고 OK 버튼을 클릭하면 입력된 정보가 preference store에 저장됩니다.



RingtonePreference는 ringtone 리스트가 있는 dialog box를 보여줄 겁니다. 그리고 사용자가 default ringtone이나 silent mode를 선택할 수 있도록 합니다. 여기에 android:key 속성에는 Audio라고 설정이 돼 있습니다. 그리고 title은 Select sound라고 돼 있죠. android:ringtoneType은 display 될 ringtone 리스트를 정합니다. 여기에 들어갈 수 있는 값은 ringtone, notification, alarm 그리고 all 이 들어갈 수 있습니다.



ListPreference 에는 radio 버튼 형식으로 preference들의 세트를 dialog box 에 보여 줍니다. 사용자가 그 중 하나를 선택할 수 있는 거죠. 이 dialog box의 title은 Choose a product 가 될 겁니다. android:key 속성에는 product_list가 대입 됐구요. android:endtries 속성은 preference들의 리스트를 보여주기 위해 ListPreference에 product라는 이름의 배열이 할당됐습니다. 이 배열에 있는 값들이 ListPreference를 통해서 표시되는 radio button들의 아이템이 될 겁니다. android:entryValues 속성은 prodselected라고 하는 다른 배열을 정의하는데요. product 배열에 정의된 요소들의 값을 잡아두고 있기 위해서 세팅됐습니다. android:entryValues 속성은 사용자가 선택한 radio button에 해당되는 값들을 저장하는 배열입니다.



<Preference> element는 PreferenceFragment에 Submit Button을 표시합니다. 이 Submit button은 여기서 android:key 속성에 해당되는 값이 submitPref로 돼 있습니다. 자바코드에서 이 값을 갖고 콘트롤 할 겁니다.



이제 strings.xml에 두개의 배열을 정의할 겁니다. 하나는 ListPreference의 radio button에 표시될 텍스트들이구요 다른 하나는 첫번째 배열과 대응하는 값들 입니다. 이 xml은 res/values 폴더 안에 있게 됩니다.



strings.xml



<?xml version="1.0" encoding="utf-8"?>
<resources>
    <string name="app_name">PrefFragmentApp</string>
    <string name="menu_settings">Settings</string>
    <string-array name="products">
        <item>Camera</item>
        <item>Laptop</item>
        <item>Watch</item>
        <item>Smartphone</item>
        <item>Television</item>
    </string-array>
    <string-array name="prodselected">
        <item>You have selected Camera</item>
        <item>You have selected Laptop</item>
        <item>You have selected Watch</item>
        <item>You have selected Smartphone</item>
        <item>You have selected Television</item>  
    </string-array>
</resources>


products 배열에 있는 element들은 ListPreference에 보이는 radio buttons 옆에 표시될 텍스트 들입니다. prodselected 배열은 위 products 배열중에서 선택된 것들에 대한 return 값들이 들어 있습니다.



preference.xml에 있는 이 preference view들을 load 하기 위한 자바클래스가 필요 합니다. 아래 그 샘플 코드가 있습니다.



PrefFragActivity.java



public class PrefFragActivity extends Activity {
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        getFragmentManager().beginTransaction().replace(android.R.id.content, new PrefsFragment()).commit();
    }

    public static class PrefsFragment extends PreferenceFragment  {
        @Override
        public void onCreate(Bundle savedInstanceState) {
            super.onCreate(savedInstanceState);
            addPreferencesFromResource(R.xml.preferences);
            Preference submitPref = (Preference) findPreference("submitPref");
            submitPref.setOnPreferenceClickListener(new OnPreferenceClickListener() {
                public boolean onPreferenceClick(Preference preference) {
                    getActivity().finish();
                    return true;
                }
            });
        }
    }
}



PreferenceFragment를 사용하기 위해 자바 클래스에서 PreferenceFragment를 extends 합니다. addPreferencesFromResource() 메소드는 XML 파일(preferences.xml)에 있는 PreferenceFragment에 있는 preference view를 load하기 위해 호출됩니다. preferences.xml에서 <Preference) element를 사용해 정의된 Submit 버튼은 submitPref라는 Preference 객체를 통해서 접근되고 매핑이 됩니다. 이것의 콜백 메소드인 onPreferenceClick()은 submitPref 객체가 클릭됐을 떄 실행됩니다. 이 onPreferenceClick() 메소드는 이 activity를 finish() 하고 선택된 preferences에 필요한 action을 하기 위해 PreferenceFragActivity.java로 돌아 갑니다. 이 PrefFragmentAppActivity자바 activity 파일을 통해 텍스트뷰에 유저가 선택한 preference를 표시할 겁니다.



이 PreferenceFragment에 보여지는 preference view들로부터 선택된 옵션을 표시하기 위해 4개의 텍스트뷰가 정의되어야 합니다. 아래 그 layout xml 파일이 있습니다.



activity_pref_fragment_app.xml



<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:orientation="vertical" >
    <TextView
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:id="@+id/newsletter"
        android:textSize="@dimen/text_size"        
        android:textStyle="bold" />
    <TextView
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:id="@+id/name"
        android:textSize="@dimen/text_size"
        android:textStyle="bold" />
    <TextView
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:id="@+id/ringtone"
        android:textSize="@dimen/text_size"
        android:textStyle="bold" />
    <TextView
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:id="@+id/product"
        android:textSize="@dimen/text_size"
        android:textStyle="bold" />
</LinearLayout>



위 layout xml 파일을 보면 4개의 텍스트뷰가 있고 각각 id 는 각각 newsletter, name, ringtone, product 입니다. 이 텍스트뷰는 LinearLayout 안에서 아래 위로 배치됩니다. newsletter 텍스트뷰에는 CheckBoxPreference의 체크박스에 유저가 체크했는지 여부가 표시될 겁니다. name 텍스트뷰는 EditTextPreference에 유저가 입력한 이름이 표시될것이고 ringtone 텍스트뷰는 유저가 선택한 RingtonePreference의 ringtone이 표시될 겁니다. product 텍스트뷰에는 ListPreference에서 유저가 선택한 product가 표시됩니다.



PreferenceFragment를 표시하고 사용자가 선택한 preference들을 보여주기위해 아래와 같은 자바파일을 만듭니다.



PrefFragmentAppActivity.java



public class PrefFragmentAppActivity extends Activity {
    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_pref_fragment_app);
        startActivity(new Intent(this, PrefFragActivity.class));
    }

    @Override
    public void onResume() {
        super.onResume();
        SharedPreferences prefs=PreferenceManager.getDefaultSharedPreferences(this);
        TextView newsletter=(TextView)findViewById(R.id.newsletter);
        TextView name=(TextView)findViewById(R.id.name);
        TextView ringtone=(TextView)findViewById(R.id.ringtone);
        TextView product=(TextView)findViewById(R.id.product);
        if(Boolean.valueOf(prefs.getBoolean("Newskey", false)))
            newsletter.setText("You have selected Newsletter");
        else
            newsletter.setText("");
        ringtone.setText("The ringtone selected is "+prefs.getString("Audio", "Silent"));
        name.setText("The name entered is "+prefs.getString("Namekey",""));
        String selectedProduct = prefs.getString("products_list", "Camera");
        product.setText(selectedProduct);
    }
}



이 PreferenceFragment를 표시하기 위해 PrefFragActivity 클래스가 시작됩니다. PreferenceFragment에서 사용자가 선택한 preferences를 보여주기 위해 activity_pref_fragment_app.xml 인 layout 파일에 텍스트 뷰들이 정의돼 있습니다. 이 preference 뷰들에서 선택된 옵션을 찾기 위해  prefs로 명명된 SharedPreferences 객체를 생성했습니다. getInt(), getString(), getBoolean() 메소드를 통해 이 SharedPreferences 객체로부터 그 값들을 수집합니다.



CheckBoxPreference의 값을 읽기 위해서는 getBoolean() 메소드를 사용하고 CheckBoxPreference의 key를 전달해서 값을 받습니다. 이 Newskey라는 key가 SharedPreference 인스턴스의 getBoolean()메소드를 통해 전달 됐을 때 이 CheckBoxPreference는 true나 false 를 return 할 겁니다.


그리고 EditTextPreference는 SharedPreference 인스턴스의 getString()메소드로 Namekey라는 key를 전달합니다. 디폴트는 empty string 입니다. RingtonePreference와 ListPreference도 Audio와 product_list라는 key 값을 SharedPreference인스턴스의 getString() 메소드를 통해서 전달합니다. preference view들에서 사용자에 의해 선택된 preference들은 택스트뷰들을 통해 표시됩니다. ringtone의 디폴트값은 Silent 이고 product는 Camera 입니다.



이 PrefFragActivity.java 를 안드로이드에 보이도록 하려면 아래 코드를 AndroidManifest.xml에 추가하셔야 합니다.



<activity android:name=".PrefFragActivity" android:label="@string/app_name" />



Summary
 
 이 챕터에서는 fragments의 사용법과 다른 화면 크기에 맞게 어플리케이션을 적용하는 방법에 대해 다뤘습니다. fragment life cycle과 runtime시 동적으로 이 fragment를 추가하는 방법도 다뤘습니다. 그리고 fragment들 사이에 데이터를 전달하고 받는 방법도 배웠습니다. 그리고 ListFragment, DialogFragment 그리고 PreferenceFragment에 대해서도 배웠습니다.


반응형

Comment