• 【起航计划 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变化时在屏幕上显示当前按键的次数:

  • 相关阅读:
    交叉熵损失函数
    均方根误差(RMSE),平均绝对误差(MAE),标准差(Standard Deviation)
    【转载】【矩阵,数组,列表之间相互转化】
    【数据集介绍】【Point04】
    【视频处理知识】
    【IOU】
    【模型训练】
    【图片操作】
    python 写 XML 文件
    【数组操作】 创建、排序
  • 原文地址:https://www.cnblogs.com/dongdong230/p/4324228.html
Copyright © 2020-2023  润新知