SharedPreferences 使用base64保存复杂对象
本篇博文建议电脑看,因为要对应码表
什么是base64:
base64是编码方式之一
什么是编码方式(base64):
编码方式是信息从一种格式转换为另一种格式的过程
看到比较的多编码方式有:ASCII,GBK,Unicode…
base64是为了解决什么而出现的:
通俗的说就是以前的邮件网络传送,只能传送我们肉眼看到的字符,而看不到的字符不可以发送,
比如换行符啊,空格,回车。为了解决传送不了这些不可见字符,所以就出现了base64编码方式。
我对base64的通俗理解:
base64其实就是使用了64个肉眼可以看到的字符来表示二进制,而计算中的数据都是使用二进制表示
通俗的说:就是使用64个看的到的字符表示了所有数据:包括肉眼可见的和肉眼不可见的
base64的64个字符是啥:(看图,来自维基百科:https://en.wikipedia.org/wiki/Base64)
可以看到value是0-63,char是"A-Z、a-z、0-9" 一个加号和一个斜杆(刚好总共64个)
我理解的索引表(base64):
索引表都是约定俗成的,固定的value表示固定的char,就好像加法表一样,1+1=2,这个是固定的了,解析不了为啥,比如:1+1=2
字节和位(base64)
我们都知道一个字节等于八位。而想表示base64索引表中的value:0-63,要多少字节呢,答案:不需要一个字节(8位),只需要6位就可以表示,
十进制的0-63只要二进制的111111(6位)就可以表示玩了
00000000 转换为10进制 0
00111111 转换为10进制 63
如何转换为base64
字符串转为base64码,需要把字符转为ascll码中的数字,然后再把数字转换为二进制,然后再转base64
ASCII对照表(如果是直接输入,然后查询的,有的是错的(2018/6/5),还是肉眼慢慢找吧) http://ascii.911cha.com/
下面来一些例子:
首先是我的名字:
字符串: l i n x i n
ASCII 108 105 110 120 105 110
二进制8位 0110 1100 0110 1001 0110 1110 0111 1000 0110 1001 0110 1110
011011000110100101101110011110000110100101101110
6位 011011 000110 100101 101110 011110 000110 100101 101110
十进制 27 6 37 46 30 6 37 46
对应编码 b G l u e G l u
这里格式不好排,我上传一张图片
啊哈哈,对着这些数字找对应编码的时候,让我想起了国民党打仗发的电报(好像也是有一本这样的索引表)
//通过base64保存复杂对象到SharedPreferences
public static boolean saveObject(String key, Object obj, Context context) {
//如果对象为null,不保存,直接返回保存失败
if (obj == null) {
return false;
}
//flag,用于判断是否保存对象成功
boolean flag = false;
SharedPreferences preferences = PreferenceManager.getDefaultSharedPreferences(context);
// 内部创建一个byte型别数组的缓冲区,最初默认为32位,在需要的时候会自动增加大小,从流中读字节数组
ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream();
//主要的作用是用于写入对象信息与读取对象信息
ObjectOutputStream objectOutputStream = null;
try {
// 创建对象输出流,并封装字节流
objectOutputStream = new ObjectOutputStream(byteArrayOutputStream);
// 将对象写入字节流
objectOutputStream.writeObject(obj);
// 将字节流编码成base64的字符窜
String base64String = new String(Base64.encode(byteArrayOutputStream
.toByteArray(), Base64.DEFAULT));
flag = preferences.edit().putString(key, base64String).commit();
} catch (IOException e) {
e.printStackTrace();
} finally {
//主要做关闭流操作
try {
if (objectOutputStream != null) {
objectOutputStream.close();
}
if (byteArrayOutputStream != null) {
byteArrayOutputStream.close();
}
} catch (Exception e) {
e.printStackTrace();
}
return flag;
}
}
//读取复杂对象
public static Object getObject(String key, Context context) {
Object obj = null;
SharedPreferences preferences = PreferenceManager.getDefaultSharedPreferences(context);
String objString = preferences.getString(key, "");
// 读取字节
byte[] base64 = Base64.decode(objString.getBytes(), Base64.DEFAULT);
// 字节流
ByteArrayInputStream byteArrayInputStream = new ByteArrayInputStream(base64);
//对象流
ObjectInputStream objectInputStream = null;
try {
// 再次封装
objectInputStream = new ObjectInputStream(byteArrayInputStream);
// 读取对象
obj = objectInputStream.readObject();
} catch (Exception e) {
// e.printStackTrace();
} finally {
try {
if (objectInputStream != null) {
objectInputStream.close();
}
if (byteArrayInputStream != null) {
byteArrayInputStream.close();
}
} catch (IOException e) {
e.printStackTrace();
}
}
return obj;
}
//序列化的实体类
class Person implements Serializable {
private String firstName;
private String lastName;
public Person(String firstName, String lastName) {
this.firstName = firstName;
this.lastName = lastName;
}
@Override
public String toString() {
return lastName+firstName;
}
}
//简单用例
public class MainActivity extends AppCompatActivity {
private static final String KEY = "key";
private static final String TAG = "MainActivity";
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
Person p = new Person("lin", "xin");
if (saveObject(KEY, p, this)) {
Log.i(TAG, getObject(KEY, this).toString());
} else {
Log.i(TAG, "onCreate:失败 ");
}
}
}