zoukankan      html  css  js  c++  java
  • 在偏好文件中存储数据

    SharedPreferences对象使用常规的XML文件来存储数据,这些文件存储在应用程序的数据目录内。该XML文件的结构很简单,因为它只允许存储键/值对,不过Android API还提供了非常方便的抽象,允许开发者以类型安全的方式读写数据。

    创建SharedPreferences对象最简单的方式是使用PreferenceManager.getDefaultSharedPreferences()方法,它会返回应用程序默认的偏好对象。使用该方式来存储主要的偏好设置很方便,因为框架会自动管理好文件名。但是,如果应用程序有多个偏好文件,最好使用Context.getSharedPreference()方法,它允许开发者自由地命名文件。如果只是创建和Activity相关的偏好文件,可以使用Activity.getPreference()方法,它会在调用时得到Activity的名字。

    PreferenceManager.getDefaultSharedPreferences()创建的偏好文件名是由包名以及后缀_preferences组成的,如com.liyuanjinglyj.code_preferences。虽然很少需要这个名字,但如果要实现文件备份代理该名字就很重要。

    SharedPreferences支持的存储值的类型有int,float.long.boolean,String以及set<String>对象。键名必须是一个有效的字符串,常见的做法是使用点符号按组结构化多个键值。

    例如,如果偏好文件包含用于网络配置以及用户界面设置相关的值,可以通过为每个键添加network或者ui前缀来把它们分组。通过该方式,开发者可以轻松的管理键/值对,避免命名冲突。下面的例子演示了如何通过使用前缀并在单独的Java接口文件中定义键来结构化偏好数据:

    public interface Constants {
        public static final String NETWORK_PREFIX = "network.";
        public static final String UI_PREFIX = "ui.";
        public static final String NETWORK_RETRY_COUNT
    = NETWORK_PREFIX + "retryCount";
        public static final String NETWORK_CONNECTION_TIMEOUT
    = NETWORK_PREFIX + "connectionTimeout";
        public static final String NETWORK_WIFI_ONLY
    = NETWORK_PREFIX + "wifiOnly";
        public static final String UI_BACKGROUND_COLOR
    = UI_PREFIX + "backgroundColor";
        public static final String UI_FOREGROUND_COLOR
    = UI_PREFIX + "foregroundColor";
        public static final String UI_SORT_ORDER
    = UI_PREFIX + "sortOrder";
        public static final int SORT_ORDER_NAME = 10;
        public static final int SORT_ORDER_AGE = 20;
        public static final int SORT_ORDER_CITY = 30;
    }

    推荐使用上面的方法访问存储的偏好值,而不是把键名硬编码在代码中。这样做可以避免误拼写,从而减少由于拼写导致的bug。

    下面的代码演示了使用之前定义的Constants类来访问偏好文件:

    private void readUiPreferences() {
        SharedPreferences preferences
                = PreferenceManager.getDefaultSharedPreferences(this);
        int defaultBackgroundColor = getResources().
                getColor(R.color.default_background);
        int backgroundColor = preferences.getInt(
                Constants.UI_BACKGROUND_COLOR,
    defaultBackgroundColor);
    View view = findViewById(R.id.background_view);
    view.setBackgroundColor(backgroundColor);
    }

    要修改存储在偏好文件中的值,首先需要获取Editor实例,它提供了相应的PUT方法,以及用于提交修改的方法。在Android2.3之前,通过使用commit()方法把修改同步提交到存储设备中。但在2.3版本中,Editor提供了用于异步执行写操作的apply()方法。因为要尽可能地避免在主线程执行阻塞的操纵,apply()方法比之前的commit()方法更好。这使得在主线程直接从UI操作更新SharedPreferences很安全。

    public void doToggleWifiOnlyPreference(View view) {
        SharedPreferences preferences = PreferenceManager.
                getDefaultSharedPreferences(this);
        boolean currentValue = preferences.
                getBoolean(Constants.NETWORK_WIFI_ONLY, false);
    preferences.edit()
                .putBoolean(Constants.NETWORK_WIFI_ONLY, !currentValue)
                .apply();
    }

    上面的代码显示了使用点击监听器来切换存储在Constants.NETWORK_WIFI_ONLY中的偏好值。如果使用之前的commit()方法,主线程可能会被阻塞,导致用户体验差。使用apply()方法就不需要担心上面的问题。

    在同一个进程中,每个偏好文件都只有实例。所以即便从二个不同的组件使用相同的名字获取二个SharedPreference对象,它实际上还是共享同一个实例,所以对于一个对象的改变会立即影响到另一个对象。

    为了能在偏好值被修改的时候收到通知,开发者需要注册一个监听器回调函数,每当调用apply()或者commit()方法时都会触发该监听器回调函数。最常见的例子是,在Activity中修改偏好值应该影响后台Service的行为,如下所示:

    public class NetworkService extends IntentService
            implements SharedPreferences.OnSharedPreferenceChangeListener {
        public static final String TAG = "NetworkService";
        private boolean mWifiOnly;
        public NetworkService() {
            super(TAG);
    }
    
        @Override
    public void onCreate() {
            super.onCreate();
    SharedPreferences preferences = PreferenceManager
                    .getDefaultSharedPreferences(this);
    preferences.registerOnSharedPreferenceChangeListener(this);
    mWifiOnly = preferences.getBoolean(Constants.NETWORK_WIFI_ONLY,
                    false);
    }
    
        @Override
    protected void onHandleIntent(Intent intent) {
            ConnectivityManager connectivityManager
                    = (ConnectivityManager)
                    getSystemService(CONNECTIVITY_SERVICE);
    NetworkInfo networkInfo
                    = connectivityManager.getActiveNetworkInfo();
            int type = networkInfo.getType();
            if (mWifiOnly && type != ConnectivityManager.TYPE_WIFI) {
                Log.d(TAG, "只执行WIFI网络");
                return;
    }
    
            performNetworkOperation(intent);
    }
    
        @Override
    public void onSharedPreferenceChanged(SharedPreferences preferences,
    String key) {
            if (Constants.NETWORK_WIFI_ONLY.equals(key)) {
                mWifiOnly = preferences
                        .getBoolean(Constants.NETWORK_WIFI_ONLY, false);
                if(mWifiOnly) {
                    cancelNetworkOperationIfNecessary();
    }
            }
        }
    
        @Override
    public void onDestroy() {
            super.onDestroy();
    SharedPreferences preferences = PreferenceManager
                    .getDefaultSharedPreferences(this);
    preferences.unregisterOnSharedPreferenceChangeListener(this);
    }
    
        private void cancelNetworkOperationIfNecessary() {
            // 取消网络操作。
    }
    
        private void performNetworkOperation(Intent intent) {
            // 连上网络操作
    }
    }
    

    版权声明:本文为博主原创文章,未经博主允许不得转载。

  • 相关阅读:
    强连通分量填坑记
    Car的旅行路线
    油滴扩散
    【转】孔乙已
    [CQOI2007]余数求和
    树形dp入门两题
    一本通 3.1 例 1」黑暗城堡
    一点点有的没的和一年总结
    leetcode答案 有效的括号(python)
    leetcode数据库题目及答案汇总
  • 原文地址:https://www.cnblogs.com/liyuanjinglyj/p/4656562.html
Copyright © 2011-2022 走看看