6.2 数据储存-SharedPreferences

标注:本文为个人学习使用,仅做自己学习参考使用,请勿转载和转发
2018-08-01: 初稿,最近晚上的天气太热了,沉不下心,理由太多,参考博主coder-pig

0. 引言

  • 这个是Android的第二种储存的方式,使用SharedPreferences。
  • 这个SharedPreferences类似一个键值对的储存,使用的好像是xml的格式的存储方法,写在内存里面,一般用来储存用户的偏好信息、登陆账号密码等,但是密码不能用明文存啊!

1. SharedPreferences

使用流程图

实现代码示例
运行效果图
流程是输入账号密码后点击登录,将信息保存到SharedPreference文件中, 然后重启app,看到数据已经显示在文本框中了


另外保存后,我们可以在File Expoler打开data/data/<包名>可以看到在shared_prefs目录下 生成了一个xml文件(因为N5没root,这里找了以前的效果图):

点击导出到桌面可以看到里面的内容:


代码实现
编写简单的SP工具类:SharedHelper.java:

public class SharedHelper {

    private Context mContext;

    public SharedHelper() {
    }

    public SharedHelper(Context mContext) {
        this.mContext = mContext;
    }


    //定义一个保存数据的方法
    public void save(String username, String passwd) {
        SharedPreferences sp = mContext.getSharedPreferences("mysp", Context.MODE_PRIVATE);
        SharedPreferences.Editor editor = sp.edit();
        editor.putString("username", username);
        editor.putString("passwd", passwd);
        editor.commit();
        Toast.makeText(mContext, "信息已写入SharedPreference中", Toast.LENGTH_SHORT).show();
    }

    //定义一个读取SP文件的方法
    public Map read() {
        Map data = new HashMap();
        SharedPreferences sp = mContext.getSharedPreferences("mysp", Context.MODE_PRIVATE);
        data.put("username", sp.getString("username", ""));
        data.put("passwd", sp.getString("passwd", ""));
        return data;
    }
}

最后是MainActivity.java实现相关逻辑:

public class MainActivity extends AppCompatActivity {

    private EditText editname;
    private EditText editpasswd;
    private Button btnlogin;
    private String strname;
    private String strpasswd;
    private SharedHelper sh;
    private Context mContext;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        mContext = getApplicationContext();
        sh = new SharedHelper(mContext);
        bindViews();
    }

    private void bindViews() {
        editname = (EditText)findViewById(R.id.editname);
        editpasswd = (EditText)findViewById(R.id.editpasswd);
        btnlogin = (Button)findViewById(R.id.btnlogin);
        btnlogin.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                strname = editname.getText().toString();
                strpasswd = editpasswd.getText().toString();
                sh.save(strname,strpasswd);
            }
        });
    }

    @Override
    protected void onStart() {
        super.onStart();
        Map data = sh.read();
        editname.setText(data.get("username"));
        editpasswd.setText(data.get("passwd"));
    }
}

2. 读取其他应用的SharedPreferences

  • 读取其他应用的Context,这个Context代表访问该app的全局信息的接口,而决定应用的唯一标识,就是包名,所以我们应该通过包名获得对应的app的Context
  • 另外注意的是,其他的应用SP文件是否指定了可读或者可写的权限,我们上面创建的是MODE_PRIVATE的就不可以了,所以就想读别人SP里的数据是比较难的,比如将密码保存在SP中,一般也是会做加密处理的。
    实现流程图


代码示例:
运行效果图

代码实现
我们读取SP的操作放在MainActivity.java中完成,点击按钮后读取SP,并通过Toast显示出来:

public class MainActivity extends AppCompatActivity {

    private Context othercontext;
    private SharedPreferences sp;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        Button btnshow = (Button) findViewById(R.id.btnshow);
        btnshow.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                //获得第一个应用的包名,从而获得对应的Context,需要对异常进行捕获
                try {
                    othercontext = createPackageContext("com.jay.sharedpreferencedemo", Context.CONTEXT_IGNORE_SECURITY);
                } catch (PackageManager.NameNotFoundException e) {
                    e.printStackTrace();
                }
                //根据Context取得对应的SharedPreferences
                sp = othercontext.getSharedPreferences("mysp", Context.MODE_WORLD_READABLE);
                String name = sp.getString("username", "");
                String passwd = sp.getString("passwd", "");
                Toast.makeText(getApplicationContext(), "Demo1的SharedPreference存的\n用户名为:" + name + "\n密码为:" + passwd, Toast.LENGTH_SHORT).show();
            }
        });
    }
}

3. 对SP文件中重要的数据进行加密

  • 用户名密码就要想办法进行加密了,不能裸奔,这样就容易泄漏了
3.1. 简单的加密处理流程

流程图如下


Step 1. 用户注册账号密码,账号密码校验后(账号是否重复,密码位数 > 6位等), 即账号密码有效,注册成功后,我们提交给服务器的账号,以及本地加密过的密码!
Step 2.服务器端将用户提交的账号,加密过的密码保存到服务端的数据库中,也就是服务 端并不会保存我们的明文密码(原始)密码!
Step 3.说回客户端,如果注册成功或者登陆成功,你想保存账号密码到SP中,保存的的密码 也需要走一趟加密流程!即明文密码——>加密,再保存!如果不保存,每次请求的时候,明文密码 也要走一趟家里流程,然后拿着加密后的密码来请求服务器!
Step 4.服务器验证账号以及加密密码,成功,分配客户端一个session标识,后续客户端可以拿着 这个session来访问服务端提供的相关服务!

3.2 MD5简单介绍

1)MD5是什么?
Message Digest Algorithm MD5(中文名为消息摘要算法第五版)为计算机安全领域广泛 使用的一种散列函数,用以提供消息的完整性保护——摘自《百度百科》 简单点说就是一种加密算法,可以将一个字符串,或者文件,压缩包,执行MD5加密后, 就可以生产一个固定长度为128bit的串!这个串基本唯一!另外我们都知道:一个十六进制 需要用4个bit来表示,那么对应的MD5的字符串长度就为:128 / 4 = 32位了!另外可能 你看到一些md5是16位的,只是将32位MD5码去掉了前八位以及后八位!不信么,我们来试试 百度一下:md5在线解密,第一个:http://www.cmd5.com/


2)MD5能破解吗?
答:MD5不可逆,就是说没有对应的算法,无法从生成的md5值逆向得到原始数据! 当然暴力破解除外,简单的MD5加密后可以查MD5库~
3)MD5值唯一吗?
答:不唯一,一个原始数据只对应一个MD5值,但是一个MD5值可能对应多个原始数据!

3.MD5加密实现例子:
其实网上有很多写好的MD5的例子,百度或者谷歌一搜一大堆,这里提供下小猪用的MD5加密工具类!
Md5Util.java:

public class MD5 {
    public static String getMD5(String content) {
        try {
            MessageDigest digest = MessageDigest.getInstance("MD5");
            digest.update(content.getBytes());
            return getHashString(digest);
        } catch (NoSuchAlgorithmException e) {
            e.printStackTrace();
        }
        return null;
    }

    private static String getHashString(MessageDigest digest) {
        StringBuilder builder = new StringBuilder();
        for (byte b : digest.digest()) {
            builder.append(Integer.toHexString((b >> 4) & 0xf));
            builder.append(Integer.toHexString(b & 0xf));
        }
        return builder.toString();
    }
}

MainActivity.java直接调用getMD5这个静态方法:

Log.e("HeHe", MD5.getMD5("呵呵"));

我们可以看到Logcat上打印出:


这就是加密过后的呵呵了,我们可以把这串密文拷贝到上面这个md5的在线解密网站:


嘿嘿,果然,只是这样加密一次,就直接破解了,有点不安全的样子,那就加密100次咯, 就是将加密后的字符串再加密,重复100次,我们在原先的基础上加个加密一百次的方法:

public static String getMD5x100(String content){
    String s1 = content;
    for(int i = 0;i < 100;i++){
        s1 = getMD5(s1);
    }
    return s1;
}

然后调用下,发现打印这个的Log:

复制界面网站上:

好的,装B成功~

4. SharedPreference工具类:

  • 每次都要自行实例化SP相关的类,肯定很麻烦,这里贴个SP的工具类,大家可以贴到 自己的项目中,工具类来源于鸿洋大神的blog~
    SPUtils.java
public class SPUtils {
    /**
     * 保存在手机里的SP文件名
     */
    public static final String FILE_NAME = "my_sp";
    /**
     * 保存数据
     */
    public static void put(Context context, String key, Object obj) {
        SharedPreferences sp = context.getSharedPreferences(FILE_NAME, context.MODE_PRIVATE);
        SharedPreferences.Editor editor = sp.edit();
        if (obj instanceof Boolean) {
            editor.putBoolean(key, (Boolean) obj);
        } else if (obj instanceof Float) {
            editor.putFloat(key, (Float) obj);
        } else if (obj instanceof Integer) {
            editor.putInt(key, (Integer) obj);
        } else if (obj instanceof Long) {
            editor.putLong(key, (Long) obj);
        } else {
            editor.putString(key, (String) obj);
        }
        editor.commit();
    }


    /**
     * 获取指定数据
     */
    public static Object get(Context context, String key, Object defaultObj) {
        SharedPreferences sp = context.getSharedPreferences(FILE_NAME, context.MODE_PRIVATE);
        if (defaultObj instanceof Boolean) {
            return sp.getBoolean(key, (Boolean) defaultObj);
        } else if (defaultObj instanceof Float) {
            return sp.getFloat(key, (Float) defaultObj);
        } else if (defaultObj instanceof Integer) {
            return sp.getInt(key, (Integer) defaultObj);
        } else if (defaultObj instanceof Long) {
            return sp.getLong(key, (Long) defaultObj);
        } else if (defaultObj instanceof String) {
            return sp.getString(key, (String) defaultObj);
        }
        return null;
    }

    /**
     * 删除指定数据
     */
    public static void remove(Context context, String key) {
        SharedPreferences sp = context.getSharedPreferences(FILE_NAME, context.MODE_PRIVATE);
        SharedPreferences.Editor editor = sp.edit();
        editor.remove(key);
        editor.commit();
    }


    /**
     * 返回所有键值对
     */
    public static Map getAll(Context context) {
        SharedPreferences sp = context.getSharedPreferences(FILE_NAME, context.MODE_PRIVATE);
        Map map = sp.getAll();
        return map;
    }

    /**
     * 删除所有数据
     */
    public static void clear(Context context) {
        SharedPreferences sp = context.getSharedPreferences(FILE_NAME, context.MODE_PRIVATE);
        SharedPreferences.Editor editor = sp.edit();
        editor.clear();
        editor.commit();
    }

    /**
     * 检查key对应的数据是否存在
     */
    public static boolean contains(Context context, String key) {
        SharedPreferences sp = context.getSharedPreferences(FILE_NAME, context.MODE_PRIVATE);
        return sp.contains(key);
    }
}

你可能感兴趣的:(6.2 数据储存-SharedPreferences)