Android数据存储---SharedPreferences详解及应用

简述:

     在Android开发中,如果站在开发者的角度来讲,其存储方式大致分为5种,下面我就先简单介绍一下这几种存储方式,在本篇博文中谈谈SharedPreferences的用法并封装一个在开发中常用的SharedPreferences的工具类,并在以后的几篇博文中一一谈谈其他几种Android的存储方式,OK,废话不多说,看看下面的存储方式:
   1、SharedPreferences
         Store private primitive data in key-value pairs.
         以键值对的形式保存私有的简单数据。
   2、Internal Storage
         Store private data on the device memory.
         在手机内存中保存不对外共享的信息。
  3、External Storage
        Store public data on the shared external storage.
        在外部存储设备上保存公共的数据信息。主要指保存在SDCard上。
  4、SQLite Databases
        Store structured data in a private database.
       将结构化的数据保存进数据库。
  5、Network Connection
       Store data on the web with your own network server.
     将数据保存到自己的远程服务器上。


SharedPreferences基本用法:

概念:
     SharedPreferences是Android系统提供的一个通用的数据持久化框架,用于存储和读取key-value类型的原始基本数据类型对,目前支持string、int、long、float、boolean等基本类型的存储,对于自定义的对象数据类型,无法使用SharedPreferences来存

应用场景
      SharedPreferences主要用于存储系统的配置信息,比如保存用户登录时的用户名、密码以及第一次安装或升级App时加载欢迎页面,再有就是一些App的配置信息,例如手势锁密码、音效等。

API介绍

   (1)获得SharedPreferences对象:
           SharedPreferences sp=Context.getSharedPreferences(String name, int mode);
           SharedPrefrences sp =Activity.getPreferences(int mode);
           两者的区别:
           getSharedPreferences是Context类中的方法,可以指定file name以及mode。

           getPreferences是Activity类中的方法,只需指定mode。


         备注:mode参数(该参数用来指定SharedPreferences文件的访问权限)
        Context.MODE_PRIVATE: 默认的操作模式,代表该文件是私有数据,指定该SharedPreferences的数据只能被本应用App程序读、写,写入的内容也会覆盖原文件的内容。
        Context.MODE_WORLD_READABLE: 指定 SharedPreferences数据能被其他应用App程序读,但是不支持写。
        Context.MODE_WORLD_WRITEABLE: 指定 SharedPreferences数据能被其他应用程序读、写。

       Context.MODE_APPEND:该模式会检查文件是否存在,存在就往文件追加内容,否则就创建新文件。

      最后关于SharedPreferences本身是一个接口,无法直接创建实例,通过Context的getSharedPreferences(String name, int  mode)方法来获取实例。而通过这个方法创建出来的对象有点单例模式的意思,所以在读取SharedPreferences数据时只需写入正确的“文件名”就OK了。


(2)写入数据
         在SharedPrefrences的源码中有一个内部类Editor,这个内部类承担了“写”数据的任务,其用法如下:
        SharedPreferences.Editor editor = sharedPreferences.edit();
        editor.putBoolean(String key, boolean value);
        editor.putFloat(String key, float value);
        editor.putInt(String key, int value);
        editor.putLong(String key, long value);
        editor.putString(String key, String value);
     注意最后不要忘记调用editor.commit();方法,否则数据不会被保存进去的。

   在这里还需要补充一下,SharedPreferences文件最终以xml文件形式存储在/data/data/包名/shared_prefs目录下,形式如下:

   

    <?xml version='1.0' encoding='utf-8' standalone='yes' ?>
    <map>
           <string name="pwd">123456</string>
           <string name="username">tinyjoy</string>
           <int name="age">24</int>
     </map>

       所以在向SharedPreferences文件中写入数据时是以key-value键值对的形式。

(3)读取数据
          与写入数据时的数据写入类型相对应,读取数据有以下几种方法:
          getAll()
          getBoolean(String key, boolean defValue)
          getFloat(String key, float defValue)
          getInt(String key, int defValue)
          getLong(String key, long defValue)
          getString(String key, String defValue)

(4)删除数据
         删除数据有两个方法:
        remove(String key);//删除指定”键“的那条数据。
        clear();//删除整个SharedPreferences文件

       另外还需要提醒一下:SharedPreferences文件保存在安装App的文件中,当我们把App卸载后相应的SharedPreferences文件也就一起被删除了。SharedPreferences的用法相对比较简单,基本的用法大致就这些了,那么接下来我们就封装一个工具类,这样就在做项目是减轻些负担。

SharedPreferences保存对象

     SharedPreferences只能保存一些简单的数据,那么对于复杂数据如一个User对象怎么办呢?对于对象的保存一般方式为:对象首先要实现序列化Serializable,然后将该对象转化为String类型保存起来,我们读取的时候再将String类型反序列化。对于Serializable转化为String,以及反序列化可以采用Base64或者16进制的方法。

    案例:

   

public class User implements Serializable {
    private String name;
    private String sex;

    public User() {
    }

    public User(String name, String sex) {
        this.name = name;
        this.sex = sex;
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public String getSex() {
        return sex;
    }

    public void setSex(String sex) {
        this.sex = sex;
    }

    @Override
    public String toString() {
        return "User{" +
                "name='" + name + '\'' +
                ", sex='" + sex + '\'' +
                '}';
    }
}
    转化采用16进制的转换:
/**
     * 方法描述:将数组转为16进制
     */
    private static String bytesToHexString(byte[] bArray) {
        if (bArray == null) {
            return null;
        }
        if (bArray.length == 0) {
            return "";
        }
        StringBuffer sb = new StringBuffer(bArray.length);
        String sTemp;
        for (int i = 0; i < bArray.length; i++) {
            sTemp = Integer.toHexString(0xFF & bArray[i]);
            if (sTemp.length() < 2)
                sb.append(0);
            sb.append(sTemp.toUpperCase());
        }
        return sb.toString();
    }

    /**
     * 方法描述:将16进制的数据转为数组
     *
     * @param data
     * @return modified:
     */
    private static byte[] StringToBytes(String data) {
        String hexString = data.toUpperCase().trim();
        if (hexString.length() % 2 != 0) {
            return null;
        }
        byte[] retData = new byte[hexString.length() / 2];
        for (int i = 0; i < hexString.length(); i++) {
            int int_ch;  // 两位16进制数转化后的10进制数
            char hex_char1 = hexString.charAt(i); 两位16进制数中的第一位(高位*16)
            int int_ch1;
            if (hex_char1 >= '0' && hex_char1 <= '9')
                int_ch1 = (hex_char1 - 48) * 16;    0 的Ascll - 48
            else if (hex_char1 >= 'A' && hex_char1 <= 'F')
                int_ch1 = (hex_char1 - 55) * 16;  A 的Ascll - 65
            else
                return null;
            i++;
            char hex_char2 = hexString.charAt(i); ///两位16进制数中的第二位(低位)
            int int_ch2;
            if (hex_char2 >= '0' && hex_char2 <= '9')
                int_ch2 = (hex_char2 - 48);  0 的Ascll - 48
            else if (hex_char2 >= 'A' && hex_char2 <= 'F')
                int_ch2 = hex_char2 - 55;  A 的Ascll - 65
            else
                return null;
            int_ch = int_ch1 + int_ch2;
            retData[i / 2] = (byte) int_ch;//将转化后的数放入Byte里
        }
        return retData;
    }

    使用:

public static void saveObject(Context context, String key, Object obj) {
        try {
            // 保存对象
            SharedPreferences.Editor shareData = context.getSharedPreferences(DEFAULT_FILE_NAME, 0).edit();
            //先将序列化结果写到byte缓存中,其实就分配一个内存空间
            ByteArrayOutputStream bos = new ByteArrayOutputStream();
            ObjectOutputStream os = new ObjectOutputStream(bos);
            //将对象序列化写入byte缓存
            os.writeObject(obj);
            //将序列化的数据转为16进制保存
            String bytesToHexString = bytesToHexString(bos.toByteArray());
            //保存该16进制数组
            shareData.putString(key, bytesToHexString);
            shareData.apply();
        } catch (IOException e) {
            e.printStackTrace();
            Log.e(TAG, "对象保存失败");
        }
    }

 public static Object readObject(Context context, String key) {
        try {
            SharedPreferences sharedata = context.getSharedPreferences(DEFAULT_FILE_NAME, 0);
            if (sharedata.contains(key)) {
                String string = sharedata.getString(key, "");
                if (TextUtils.isEmpty(string)) {
                    return null;
                } else {
                    //将16进制的数据转为数组,准备反序列化
                    byte[] stringToBytes = StringToBytes(string);
                    ByteArrayInputStream bis = new ByteArrayInputStream(stringToBytes);
                    ObjectInputStream is = new ObjectInputStream(bis);
                    //返回反序列化得到的对象
                    Object readObject = is.readObject();
                    return readObject;
                }
            }
        } catch (StreamCorruptedException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        } catch (IOException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        } catch (ClassNotFoundException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }
        //所有异常返回null
        return null;
    }

工具类

      关于工具类的封装,就是为了实现代码的解耦,同时也易于提高代码的可读性,我封装的SharedPreferences的工具类如下:

package com.lzy.sharedpreferenceutil;

import android.content.Context;
import android.content.SharedPreferences;
import android.text.TextUtils;
import android.util.Log;

import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;

/**
 * 作者:lzy 
 * 邮箱:1556342503@qq.com
 */

public class SharedPreferencesUtil {
    private static final String TAG = SharedPreferencesUtil.class.getSimpleName();
    /**
     * file name of the sharedPrefrences stores data on SDCard
     */
    public static final String FILE_NAME = "share_data";

    /**
     * construct method
     */
    private SharedPreferencesUtil() {
    }

    /**
     * modifying values and store the data on the SDcard in a
     * {@link SharedPreferences} object.
     *
     * @param context The context to use. Usually your
     *                {@link android.app.Application} or
     *                {@link android.app.Activity} object.
     * @param key     The name of the preference to modify.
     * @param object  The new value for the preference.
     * @Time 2016年1月7日
     * @Author lizy18
     */
    public static void put(Context context, String key, Object object) {
        SharedPreferences sharedPreferences = context.getSharedPreferences(
                FILE_NAME, Context.MODE_PRIVATE);
        SharedPreferences.Editor editor = sharedPreferences.edit();

        if (object instanceof String) {
            editor.putString(key, (String) object);
        } else if (object instanceof Integer) {
            editor.putInt(key, (Integer) object);
        } else if (object instanceof Boolean) {
            editor.putBoolean(key, (Boolean) object);
        } else if (object instanceof Float) {
            editor.putFloat(key, (Float) object);
        } else if (object instanceof Long) {
            editor.putLong(key, (Long) object);
        } else {
            try {
                ByteArrayOutputStream bos = new ByteArrayOutputStream();
                ObjectOutputStream os = new ObjectOutputStream(bos);
                os.writeObject(object);
                String bytesToHexString = bytesToHexString(bos.toByteArray());
                editor.putString(key, bytesToHexString);
            } catch (IOException e) {
                e.printStackTrace();
                Log.e(TAG, "saving object failed!");
            }
        }
        editor.apply();
    }

    /**
     * Retrieve a series of value(including String value,Integer value,Boolean
     * value,Float value,Long value) from the preferences.
     *
     * @param context  The context to use. Usually your
     *                 {@link android.app.Application} or
     *                 {@link android.app.Activity} object.
     * @param key      key The name of the preference to retrieve.
     * @param defValue Value to return if this preference does not exist.
     * @return Returns the preference value if it exists, or defValue.
     * @Time 2016年1月7日
     * @Author lizy18
     */
    public static Object get(Context context, String key, Object defValue) {
        SharedPreferences sharedPreferences = context.getSharedPreferences(
                FILE_NAME, Context.MODE_PRIVATE);
        if (!contains(context, key)) {
            return defValue;
        }
        if (defValue instanceof String) {
            return sharedPreferences.getString(key, (String) defValue);
        } else if (defValue instanceof Integer) {
            return sharedPreferences.getInt(key, (Integer) defValue);
        } else if (defValue instanceof Boolean) {
            return sharedPreferences.getBoolean(key, (Boolean) defValue);
        } else if (defValue instanceof Float) {
            return sharedPreferences.getFloat(key, (Float) defValue);
        } else if (defValue instanceof Long) {
            return sharedPreferences.getLong(key, (Long) defValue);
        } else {
            String string = sharedPreferences.getString(key, "");
            if (TextUtils.isEmpty(string))
                return defValue;
            try {
                byte[] stringToBytes = StringToBytes(string);
                ByteArrayInputStream bis = new ByteArrayInputStream(stringToBytes);
                ObjectInputStream is = new ObjectInputStream(bis);
                return is.readObject();
            } catch (IOException | ClassNotFoundException e) {
                e.printStackTrace();
            }
        }
        return defValue;
    }

    /**
     * Removing the given preference value in the preferences.
     *
     * @param context The context to use. Usually your
     *                {@link android.app.Application} or
     *                {@link android.app.Activity} object.
     * @param key     The name of the preference to remove.
     * @Time 2016年1月7日
     * @Author lizy18
     */
    public static void remove(Context context, String key) {
        SharedPreferences sharedPreferences = context.getSharedPreferences(
                FILE_NAME, Context.MODE_PRIVATE);
        SharedPreferences.Editor editor = sharedPreferences.edit();
        editor.remove(key);
        editor.apply();
    }

    /**
     * remove <em>all</em> values from the preferences.
     *
     * @param context The context to use. Usually your
     *                {@link android.app.Application} or
     *                {@link android.app.Activity} object.
     * @Time 2016年1月7日
     * @Author lizy18
     */
    public static void clear(Context context) {
        SharedPreferences sharedPreferences = context.getSharedPreferences(
                FILE_NAME, Context.MODE_PRIVATE);
        SharedPreferences.Editor editor = sharedPreferences.edit();
        editor.clear();
        editor.apply();
    }

    /**
     * Checks whether the preferences contains a preference.
     *
     * @param context The context to use. Usually your
     *                {@link android.app.Application} or
     *                {@link android.app.Activity} object.
     * @param key     The name of the preference to check.
     * @return Returns true if the preference exists in the preferences,
     * otherwise false.
     * @Time 2016年1月7日
     * @Author lizy18
     */
    public static boolean contains(Context context, String key) {
        SharedPreferences sharedPreferences = context.getSharedPreferences(
                FILE_NAME, Context.MODE_PRIVATE);
        return sharedPreferences.contains(key);
    }

    /**
     * convert array to hexadecimal String
     */
    private static String bytesToHexString(byte[] bArray) {
        if (bArray == null) {
            return null;
        }
        if (bArray.length == 0) {
            return "";
        }
        StringBuffer sb = new StringBuffer(bArray.length);
        String sTemp;
        for (int i = 0; i < bArray.length; i++) {
            sTemp = Integer.toHexString(0xFF & bArray[i]);
            if (sTemp.length() < 2)
                sb.append(0);
            sb.append(sTemp.toUpperCase());
        }
        return sb.toString();
    }

    /**
     * 方法描述:将16进制的数据转为数组
     */
    private static byte[] StringToBytes(String data) {
        String hexString = data.toUpperCase().trim();
        if (hexString.length() % 2 != 0) {
            return null;
        }
        byte[] retData = new byte[hexString.length() / 2];
        for (int i = 0; i < hexString.length(); i++) {
            int int_ch;  // 两位16进制数转化后的10进制数
            char hex_char1 = hexString.charAt(i); 两位16进制数中的第一位(高位*16)
            int int_ch1;
            if (hex_char1 >= '0' && hex_char1 <= '9')
                int_ch1 = (hex_char1 - 48) * 16;    0 的Ascll - 48
            else if (hex_char1 >= 'A' && hex_char1 <= 'F')
                int_ch1 = (hex_char1 - 55) * 16;  A 的Ascll - 65
            else
                return null;
            i++;
            char hex_char2 = hexString.charAt(i); ///两位16进制数中的第二位(低位)
            int int_ch2;
            if (hex_char2 >= '0' && hex_char2 <= '9')
                int_ch2 = (hex_char2 - 48); // 0 Ascii - 48
            else if (hex_char2 >= 'A' && hex_char2 <= 'F')
                int_ch2 = hex_char2 - 55; // A Ascii - 65
            else
                return null;
            int_ch = int_ch1 + int_ch2;
            retData[i / 2] = (byte) int_ch;//将转化后的数放入Byte里
        }
        return retData;
    }
}

  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值