zoukankan      html  css  js  c++  java
  • 【起航计划 031】2015 起航计划 Android APIDemo的魔鬼步伐 30 App->Preferences->Advanced preferences 自定义preference OnPreferenceChangeListener

    前篇文章Android ApiDemo示例解析(31):App->Preferences->Launching preferences 中用到了Advanced preferences 中定义的AdvancedPreferences。

    本篇具体介绍AdvancedPreferences, 这个例子称为Advanced ,是因为它涉及到了自定义Preference, 并在一个工作线程中刷新某个Preference的值。

    Preference 为显示在PreferenceActivity (一般以列表显示)在某个偏好的基类。有点类似于显示在Activity中的某个View。Preference 实际存取的是对应在Shared Preferences中一项,而Preference定义的key也就是用来访问Shared Preferences的key值。

    和View一样可以自定义View,在Android中也可以自定义Preference,用来显示管理应用自定义的程序偏好。本例 MyPreference 自定义一个Preference 用来存储用户点击该Preference的次数,类型为整数,初始值定义为100。它在advanced_preferences.xml 对应的定义如下:

        <com.example.android.apis.preference.MyPreference
                android:key="my_preference"
                android:title="@string/title_my_preference"
                android:summary="@string/summary_my_preference"
                android:defaultValue="100" />

    Preference 定义了很多属性,比如Default Value, dependency, enabled, icon ,key 等等都有对应的方法来操作。并且提供了两个Listener:PreferenceChangeListener, PreferenceClickListener ,允许应用程序响应Preference值变化事件,或是用户点击Preference事件。

    这里按照MyPreference 代码顺序说明一下如何自定义一个Preference。

    1.  派生于 Preference基类。

    public class MyPreference extends Preference

     2. 和自定义View类似可以为自定义Preference 自定义Layout。 MyPreference 使用R.layout.preference_widget_mypreference  ,定义很简单只有一个TextView ,其id为mypreference_widget。 一般在构造函数中使用setWidgetLayoutResource为Preference派生类设置Layout资源。

        // This is the constructor called by the inflater
        public MyPreference(Context context, AttributeSet attrs) {
            super(context, attrs);
    
            setWidgetLayoutResource(R.layout.preference_widget_mypreference);
        }

    3.  如有需要为自定义的Layout中的View 设置属性,可以在onBindView(View view)中完成。下面代码为TextView设置值为mClickCounter。

        @Override
        protected void onBindView(View view) {
            super.onBindView(view);
    
            // Set our custom views inside the layout
            final TextView myTextView = (TextView) view.findViewById(R.id.mypreference_widget);
            if (myTextView != null) {
                myTextView.setText(String.valueOf(mClickCounter));
            }
        }

    4. 如果为该自定义Preference 在XML定义了初值,比如 MyPreference的初值android:defaultValue=”100″,我们想在代码中使用这个初值来初始化变量 mClickCounter 。mClickCounter 类型为整数,这个变量就是用来保存用户的按键次数的。

        @Override
        protected Object onGetDefaultValue(TypedArray a, int index) {
            // This preference type's value type is Integer, so we read the default
            // value from the attributes as an Integer.
            return a.getInteger(index, 0);
        }
    
        @Override
        protected void onSetInitialValue(boolean restoreValue, Object defaultValue) {
            if (restoreValue) {
                // Restore state
                mClickCounter = getPersistedInt(mClickCounter);
            } else {
                // Set state
                int value = (Integer) defaultValue;
                mClickCounter = value;
                persistInt(value);
            }
        }

    5 重载 onSaveInstanceState,onRestoreInstanceState ,这两个方法是用来临时保存或是恢复一些变量值。在Preference 调用persistInt,persistBoolean, persistString等之前,preference 对应的值还没有被保存在或是更新在Shared preferences 中,如果这时用户旋转屏幕,则造成Activity重新创建,我们需要在屏幕旋转时用户选择项会保留,可以使用 onSaveInstanceState,onRestoreInstanceState来保持一些临时数据。

        @Override
        protected Parcelable onSaveInstanceState() {
            /*
             * Suppose a client uses this preference type without persisting. We
             * must save the instance state so it is able to, for example, survive
             * orientation changes.
             */
    
            final Parcelable superState = super.onSaveInstanceState();
            if (isPersistent()) {
                // No need to save instance state since it's persistent
                return superState;
            }
    
            // Save the instance state
            final SavedState myState = new SavedState(superState);
            myState.clickCounter = mClickCounter;
            return myState;
        }
    
        @Override
        protected void onRestoreInstanceState(Parcelable state) {
            if (!state.getClass().equals(SavedState.class)) {
                // Didn't save state for us in onSaveInstanceState
                super.onRestoreInstanceState(state);
                return;
            }
    
            // Restore the instance state
            SavedState myState = (SavedState) state;
            super.onRestoreInstanceState(myState.getSuperState());
            mClickCounter = myState.clickCounter;
            notifyChanged();
        }

    其中SavedState为BaseSavedState的子类,这里不详细介绍了,而BaseSavedState实现了Parcelable接口,借用Windows平台上的Serialable,其功能和其它平台上序列化功能类似。

    6. MyPreference响应Click事件,并将按键次数存入Shared Preferences 中。

        @Override
        protected void onClick() {
            int newValue = mClickCounter + 1;
            // Give the client a chance to ignore this change if they deem it
            // invalid
            if (!callChangeListener(newValue)) {
                // They don't want the value to be set
                return;
            }
    
            // Increment counter
            mClickCounter = newValue;
    
            // Save to persistent storage (this method will make sure this
            // preference should be persistent, along with other useful checks)
            persistInt(mClickCounter);
    
            // Data has changed, notify so UI can be refreshed!
            notifyChanged();
        }

    Preference使用persistBoolean, persistFloat ,persistInt, persistLong ,persisitString 向Shared Preferences中存储数据,因为mClickCounter为整数,所以使用persistInt。 notifyChanged用于通知UI有数据变化。callChangeListener 将会调用注册过的Preference.OnPreferenceChangeListener 以通知Preference有变化。

    再来看看AdvancedPreferences,代码不是很长,如下:

    public class AdvancedPreferences extends PreferenceActivity implements OnSharedPreferenceChangeListener {
        public static final String KEY_MY_PREFERENCE = "my_preference";
        public static final String KEY_ADVANCED_CHECKBOX_PREFERENCE = "advanced_checkbox_preference";
    
        private CheckBoxPreference mCheckBoxPreference;
        private Handler mHandler = new Handler();
    
        /**
         * This is a simple example of controlling a preference from code.
         */
        private Runnable mForceCheckBoxRunnable = new Runnable() {
            public void run() {
                if (mCheckBoxPreference != null) {
                    mCheckBoxPreference.setChecked(!mCheckBoxPreference.isChecked());
                }
    
                // Force toggle again in a second
                mHandler.postDelayed(this, 1000);
            }
        };
    
        @Override
        protected void onCreate(Bundle savedInstanceState) {
            super.onCreate(savedInstanceState);
    
            // Load the XML preferences file
            addPreferencesFromResource(R.xml.advanced_preferences);
    
            // Get a reference to the checkbox preference
            mCheckBoxPreference = (CheckBoxPreference)getPreferenceScreen().findPreference(
                    KEY_ADVANCED_CHECKBOX_PREFERENCE);
        }
    
        @Override
        protected void onResume() {
            super.onResume();
    
            // Start the force toggle
            mForceCheckBoxRunnable.run();
    
            // Set up a listener whenever a key changes
            getPreferenceScreen().getSharedPreferences().registerOnSharedPreferenceChangeListener(this);
        }
    
        @Override
        protected void onPause() {
            super.onPause();
    
            // Unregister the listener whenever a key changes
            getPreferenceScreen().getSharedPreferences().unregisterOnSharedPreferenceChangeListener(this);
    
            mHandler.removeCallbacks(mForceCheckBoxRunnable);
        }
    
        public void onSharedPreferenceChanged(SharedPreferences sharedPreferences, String key) {
            // Let's do something when my counter preference value changes
            if (key.equals(KEY_MY_PREFERENCE)) {
                Toast.makeText(this, "Thanks! You increased my count to "
                        + sharedPreferences.getInt(key, 0), Toast.LENGTH_SHORT).show();
            }
        }
    
    }

    它实现了OnSharedPreferenceChangeListener,因此可以用来监听MyPreference的变化。

    Handler ,由于程序中需要从工作线程中更新Preference的值,而Preference为UI,不可以从工作线程中直接更新UI,Handler允许工作线 程来更新UI,后续有详细介绍。本例每隔1秒将Haunted preference 值变化一次(选中->不选->选中->不选 ..)

    registerOnSharedPreferenceChangeListener,unregisterOnSharedPreferenceChangeListener 用来为SharedPreferences 注册一个总的Preference 变化事件处理代码。本例中MyPreference变化时在屏幕上显示当前按键的次数:

  • 相关阅读:
    Jzoj4822 完美标号
    Jzoj4822 完美标号
    Jzoj4792 整除
    Jzoj4792 整除
    Educational Codeforces Round 79 A. New Year Garland
    Good Bye 2019 C. Make Good
    ?Good Bye 2019 B. Interesting Subarray
    Good Bye 2019 A. Card Game
    力扣算法题—088扰乱字符串【二叉树】
    力扣算法题—086分隔链表
  • 原文地址:https://www.cnblogs.com/dongdong230/p/4324228.html
Copyright © 2011-2022 走看看