《Android/OPhone开发完全讲义》连载(7):使用SharedPreferences存取复杂数据

时间:2023-01-22 14:25:49
本文为《Android/OPhone开发完全讲义》一书的内容连载。转载请注明出处

    我们知道SharedPreferences只能保存简单类型的数据,例如,String、int等。如果想用SharedPreferences存取更 复杂的数据类型(类、图像等),就需要对这些数据进行编码。我们通常会将复杂类型的数据转换成Base64编码,然后将转换后的数据以字符串的形式保存在 XML文件中。

Android SDK中并未提供Base64编码和解码库。因此,需要使用第三方的jar包。在本例中使用了Apache Commons组件集中的Codec组件进行Base64编码和解码。读者可以从如下的地址下载Codec组件的安装包。

http://commons.apache.org/codec/download_codec.cgi

    在Android工程目录的lib子目录中已经包含了Codec组件的jar包(commons-codec-1.4.jar),因此,读者可以在该工程中直接使用Codec组件。

    在本例中将一个Product类的对象实例和一个图像保存在XML文件中,并在程序重新运行后从XML文件装载Product对象和图像。下面是Product类的代码:

package  net.blogjava.mobile;
import  java.io.Serializable;
//  需要序列化的类必须实现Serializable接口
public  class  Product  implements  Serializable
{
private  String id;
private  String name;
private  float  price;
//  此处省略了属性的getter和setter方法
《Android/OPhone开发完全讲义》连载(7):使用SharedPreferences存取复杂数据 《Android/OPhone开发完全讲义》连载(7):使用SharedPreferences存取复杂数据

在存取数据之前,需要使用下面的代码创建一个SharedPreferences对象。

mySharedPreferences = getSharedPreferences("base64",Activity.MODE_PRIVATE);

其中mySharedPreferences是在类中定义的SharedPreferences类型变量。

在保存Product对象之前,需要创建Product对象,并将相应组件中的值赋给Product类的相应属性。将Product对象保存在XML文件中的代码如下:

Product product  =  new  Product();
product.setId(etProductID.getText().toString());
product.setName(etProductName.getText().toString());
product.setPrice(Float.parseFloat(etProductPrice.getText().toString()));
ByteArrayOutputStream baos 
=  new  ByteArrayOutputStream();
ObjectOutputStream oos 
=  new  ObjectOutputStream(baos);
//  将Product对象放到OutputStream中
oos.writeObject(product);
mySharedPreferences 
=  getSharedPreferences( " base64 " , Activity.MODE_PRIVATE);
//  将Product对象转换成byte数组,并将其进行base64编码
String productBase64  =  new  String(Base64.encodeBase64(baos.toByteArray()));
SharedPreferences.Editor editor 
=  mySharedPreferences.edit();
//  将编码后的字符串写到base64.xml文件中
editor.putString( " product " , productBase64);
editor.commit();

保存图像的方法与保存Product对象的方法类似。由于在保存之前,需要选择一个图像,并将该图像显示在ImageView组件中,因此,从ImageView组件中可以直接获得要保存的图像。将图象保存在XML文件中的代码如下:

ByteArrayOutputStream baos  =  new  ByteArrayOutputStream();
//  将ImageView组件中的图像压缩成JPEG格式,并将压缩结果保存在ByteArrayOutputStream对象中
((BitmapDrawable) imageView.getDrawable()).getBitmap().compress(CompressFormat.JPEG,  50 , baos);
String imageBase64 
=  new  String(Base64.encodeBase64(baos.toByteArray()));
//  保存由图像字节流转换成的Base64格式字符串
editor.putString( " productImage " , imageBase64);
editor.commit();

    其中compress方法的第2个参数表示压缩质量,取值范围是0至100,0表示最高压缩比,但图像效果最差,100则恰恰相反。在本例中取了一个中间值50。

    从XML文件中装载Product对象和图像是保存的逆过程。也就是从XML文件中读取Base64格式的字符串,然后将其解码成字节数组,最后将字节数组转换成Product和Drawable对象。装载Product对象的代码如下:

String productBase64  =  mySharedPreferences.getString( " product " "" );
//  对Base64格式的字符串进行解码
byte [] base64Bytes  =  Base64.decodeBase64(productBase64.getBytes());
ByteArrayInputStream bais 
=  new  ByteArrayInputStream(base64Bytes);
ObjectInputStream ois 
=  new  ObjectInputStream(bais);
//  从ObjectInputStream中读取Product对象
Product product  =  (Product) ois.readObject();

装载图像的代码如下:
String imageBase64  =  mySharedPreferences.getString( " productImage " , "" );
base64Bytes 
=  Base64.decodeBase64(imageBase64.getBytes());
bais 
=  new  ByteArrayInputStream(base64Bytes);
//  在ImageView组件上显示图像
imageView.setImageDrawable(Drawable.createFromStream(bais, " product_image " ));

在上面的代码中使用了Drawable类的createFromStream方法直接从流创建了Drawable对象,并使用setImageDrawable方法将图像显示在ImageView组件上。

在 这里需要提一下的是图像选择。在本例中使用了res\drawable目录中的除了icon.png外的其他图像。为了能列出这些图像,本例使用了 Java的反射技术来枚举这些图像的资源ID。基本原理是枚举R.drawable类中所有的Field,并获得这些Field的值。如果采用这个方法, 再向drawable目录中添加新的图像,或删除以前的图像,并不需要修改代码,程序就可以显示最新的图像列表。枚举图像资源ID的代码如下:
//  获得R.drawable类中所有的Field
Field[] fields  =  R.drawable. class .getDeclaredFields();
for  (Field field : fields)
{
if  ( ! " icon " .equals(field.getName()))
imageResIdList.add(field.getInt(R.drawable.
class ));
}

    运行本例后,单击【选择产品图像】按钮,会显示一个图像选择对话框,如图1所示。选中一个图像后,关闭图像选择对话框,并单击【保存】按钮。如果保存成功,将显示如图2所示的提示对话框。当再次运行程序后,会显示上次成功保存的数据。

《Android/OPhone开发完全讲义》连载(7):使用SharedPreferences存取复杂数据

《Android/OPhone开发完全讲义》连载(7):使用SharedPreferences存取复杂数据
查看base64.xml文件,会看到如下的内容:

<? xml version='1.0' encoding='utf-8' standalone='yes'  ?>
< map >
< string  name ="productImage" > /9j/4AAQSkZJRgABAQAAAQABAAD/2wBDABDsyj7yK3《Android/OPhone开发完全讲义》连载(7):使用SharedPreferences存取复杂数据《Android/OPhone开发完全讲义》连载(7):使用SharedPreferences存取复杂数据 </ string >
< string  name ="product" > rO0ABXNyABtuZXQuYmxvZ2phdmEubW9iaWxlLlByb2《Android/OPhone开发完全讲义》连载(7):使用SharedPreferences存取复杂数据《Android/OPhone开发完全讲义》连载(7):使用SharedPreferences存取复杂数据 </ string >
</ map >

    注意:虽然可以采用编码的方式通过SharedPreferences保存任何类型的数据,但作者并不建议使用SharedPreferences保存尺寸很大的数据。如果读者要存取更