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

简介:
本文为《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方法
 

在存取数据之前,需要使用下面的代码创建一个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所示的提示对话框。当再次运行程序后,会显示上次成功保存的数据。

 

 
查看base64.xml文件,会看到如下的内容:

<? xml version='1.0' encoding='utf-8' standalone='yes'  ?>
< map >
< string  name ="productImage" >/9j/4AAQSkZJRgABAQAAAQABAAD/2wBDABDsyj7yK3 </ string >
< string  name ="product" >rO0ABXNyABtuZXQuYmxvZ2phdmEubW9iaWxlLlByb2 </ string >
</ map >

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

本文转自银河使者博客园博客,原文链接http://www.cnblogs.com/nokiaguy/archive/2010/09/08/1821173.html如需转载请自行联系原作者


银河使者

相关文章
|
2天前
|
XML 存储 Java
探索安卓开发之旅:从新手到专家
【10月更文挑战第35天】在数字化时代,安卓应用的开发成为了一个热门话题。本文旨在通过浅显易懂的语言,带领初学者了解安卓开发的基础知识,同时为有一定经验的开发者提供进阶技巧。我们将一起探讨如何从零开始构建第一个安卓应用,并逐步深入到性能优化和高级功能的实现。无论你是编程新手还是希望提升技能的开发者,这篇文章都将为你提供有价值的指导和灵感。
|
1天前
|
Android开发
布谷语音软件开发:android端语音软件搭建开发教程
语音软件搭建android端语音软件开发教程!
|
9天前
|
编解码 Java Android开发
通义灵码:在安卓开发中提升工作效率的真实应用案例
本文介绍了通义灵码在安卓开发中的应用。作为一名97年的聋人开发者,我在2024年Google Gemma竞赛中获得了冠军,拿下了很多项目竞赛奖励,通义灵码成为我的得力助手。文章详细展示了如何安装通义灵码插件,并通过多个实例说明其在适配国际语言、多种分辨率、业务逻辑开发和编程语言转换等方面的应用,显著提高了开发效率和准确性。
|
8天前
|
Android开发 开发者 UED
安卓开发中自定义View的实现与性能优化
【10月更文挑战第28天】在安卓开发领域,自定义View是提升应用界面独特性和用户体验的重要手段。本文将深入探讨如何高效地创建和管理自定义View,以及如何通过代码和性能调优来确保流畅的交互体验。我们将一起学习自定义View的生命周期、绘图基础和事件处理,进而探索内存和布局优化技巧,最终实现既美观又高效的安卓界面。
21 5
|
6天前
|
JSON Java Android开发
探索安卓开发之旅:打造你的第一个天气应用
【10月更文挑战第30天】在这个数字时代,掌握移动应用开发技能无疑是进入IT行业的敲门砖。本文将引导你开启安卓开发的奇妙之旅,通过构建一个简易的天气应用来实践你的编程技能。无论你是初学者还是有一定经验的开发者,这篇文章都将成为你宝贵的学习资源。我们将一步步地深入到安卓开发的世界中,从搭建开发环境到实现核心功能,每个环节都充满了发现和创造的乐趣。让我们开始吧,一起在代码的海洋中航行!
|
8天前
|
缓存 数据库 Android开发
安卓开发中的性能优化技巧
【10月更文挑战第29天】在移动应用的海洋中,性能是船只能否破浪前行的关键。本文将深入探讨安卓开发中的性能优化策略,从代码层面到系统层面,揭示如何让应用运行得更快、更流畅。我们将以实际案例和最佳实践为灯塔,引领开发者避开性能瓶颈的暗礁。
23 3
|
5天前
|
移动开发 Java Android开发
探索Android与iOS开发的差异性与互联性
【10月更文挑战第32天】在移动开发的大潮中,Android和iOS两大平台各领风骚。本文将深入浅出地探讨这两个平台的开发差异,并通过实际代码示例,展示如何在各自平台上实现相似的功能。我们将从开发环境、编程语言、用户界面设计、性能优化等多个角度进行对比分析,旨在为开发者提供跨平台开发的实用指南。
25 0
|
6月前
|
存储 算法 安全
AVB数据解析:Android verified boot 2.0 vbmeta 数据结构解析
AVB数据解析:Android verified boot 2.0 vbmeta 数据结构解析
600 0
|
存储 Android开发
【Android 逆向】函数拦截 ( GOT 表数据结构分析 | 函数根据 GOT 表进行跳转的流程 )
【Android 逆向】函数拦截 ( GOT 表数据结构分析 | 函数根据 GOT 表进行跳转的流程 )
156 0
【Android 逆向】函数拦截 ( GOT 表数据结构分析 | 函数根据 GOT 表进行跳转的流程 )
|
机器学习/深度学习 Java Android开发
Android中需要了解的数据结构(一)
Java容器类 Java容器类是java提供的工具包,包含了常用的数据结构:集合、链表、队列、栈、数组、映射等。 Java容器主要可以划分为4个部分:List列表、Set集合、Map映射、工具类(Iterator迭代器、Enumeration枚举类、Arrays和Collections) 【文章纯干货 请仔细阅读哦!】   通过上图,可以把握两个基本主体,即Collection和Map。
下一篇
无影云桌面