【android】使用SharedPreferences存取复杂数据

简介:

SharedPreferences只能保存简单类型的数据,例如,String、int等。一般会将复杂类型的数据转换成Base64编码,然后将转换后的数据以字符串的形式保存在 XML文件中,再用SharedPreferences保存。

Base64转码使用了Apache Commons组件集中的Codec组件进行Base64编码和解码。http://commons.apache.org/codec/download_codec.cgi

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


 
 
  1. package com.xdy.demo.android.pojo;  
  2.  
  3. import java.io.Serializable;  
  4.  
  5. public class BmiPref implements Serializable {  
  6.  
  7.     private static final long serialVersionUID = 6699487519253726925L;  
  8.  
  9.     private int feet;  
  10.     private int inch;  
  11.     private String result;  
  12.     private String suggest;  
  13.       
  14.     public BmiPref(){  
  15.           
  16.     }  
  17.       
  18.     public BmiPref(int feet,int inch,String result,String suggest){  
  19.         this.feet = feet;  
  20.         this.inch = inch;  
  21.         this.result = result;  
  22.         this.suggest = suggest;  
  23.     }  
  24.       
  25.     public int getFeet() {  
  26.         return feet;  
  27.     }  
  28.     public void setFeet(int feet) {  
  29.         this.feet = feet;  
  30.     }  
  31.     public int getInch() {  
  32.         return inch;  
  33.     }  
  34.     public void setInch(int inch) {  
  35.         this.inch = inch;  
  36.     }  
  37.     public String getResult() {  
  38.         return result;  
  39.     }  
  40.     public void setResult(String result) {  
  41.         this.result = result;  
  42.     }  
  43.     public String getSuggest() {  
  44.         return suggest;  
  45.     }  
  46.     public void setSuggest(String suggest) {  
  47.         this.suggest = suggest;  
  48.     }  
  49.     @Override 
  50.     public String toString() {  
  51.         return "BmiPref [feet=" + feet + ", inch=" + inch + ", result=" 
  52.                 + result + ", suggest=" + suggest + "]";  
  53.     }  


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

 


 
 
  1. public static final String PREF = "BMI_PREF";  
  2. public static final String PREF_BASE64="base64"

 
 
  1. @Override 
  2.     protected void onPause() {  
  3.         Log.v(TAG, "onPause....");  
  4.         super.onPause();  
  5.         BmiPref bp = new BmiPref();  
  6.         bp.setFeet(field_feet.getSelectedItemPosition());  
  7.         bp.setInch(field_inch.getSelectedItemPosition());  
  8.         bp.setResult(view_result.getText().toString());  
  9.         bp.setSuggest(view_suggest.getText().toString());  
  10.           
  11.         ByteArrayOutputStream baos;  
  12.         try {  
  13.             baos = new ByteArrayOutputStream();  
  14.             ObjectOutputStream oos = new ObjectOutputStream(baos);  
  15.             oos.writeObject(bp);  
  16.             //Save user preferences. use Editor object to make changes.  
  17.             SharedPreferences settings = getSharedPreferences(PREF_BASE64, Activity.MODE_PRIVATE);  
  18.             String tmpSave = new String(Base64.encodeBase64(baos.toByteArray()));  
  19.             settings.edit()  
  20.                     .putString(PREF, tmpSave)  
  21.                     .commit();  
  22.         } catch (IOException e) {  
  23.             Log.e(TAG, e.toString());  
  24.             e.printStackTrace();  
  25.         }  
  26.     } 


保存图像的方法与保存BmiPref对象的方法类似。由于在保存之前,需要选择一个图像,并将该图像显示在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文件中装载BmiPref对象和图像是保存的逆过程。也就是从XML文件中读取Base64格式的字符串,然后将其解码成字节数组,最后将字节数组转换成BmiPref和Drawable对象。装载BmiPref对象的代码如下:
 


 
 
  1. private void restorePrefs(){  
  2.         SharedPreferences settings = getSharedPreferences(PREF_BASE64, 0);  
  3.         String tmpSaveBase64 = settings.getString(PREF, "");  
  4.         // 对Base64格式的字符串进行解码  
  5.         byte[] base64Bytes = Base64.decodeBase64(tmpSaveBase64.getBytes());  
  6.         try {  
  7.             ByteArrayInputStream bais = new ByteArrayInputStream(base64Bytes);  
  8.             ObjectInputStream ois = new ObjectInputStream(bais);  
  9.             // 从ObjectInputStream中读取Product对象  
  10.             BmiPref bp = (BmiPref) ois.readObject();   
  11.               
  12.             Log.d(TAG, "BmiPref :"+bp.toString());  
  13.             if (bp != null) {  
  14.                 field_feet.setSelection(bp.getFeet());  
  15.                 field_inch.requestFocus();  
  16.                   
  17.                 field_inch.setSelection(bp.getInch());  
  18.                 field_weight.requestFocus();  
  19.                   
  20.                 view_result.setText(bp.getResult());  
  21.                 view_suggest.setText(bp.getSuggest());  
  22.             }  
  23.         } catch (Exception e) {  
  24.             Log.e(TAG, "restorePrefs : "+e.toString());  
  25.             e.printStackTrace();  
  26.         }  
  27.     } 


装载图像的代码如下:

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保存尺寸很大的数据。



本文转自xudayu 51CTO博客,原文链接:http://blog.51cto.com/xudayu/460414,如需转载请自行联系原作者


相关文章
|
3月前
|
开发工具 Android开发 开发者
Android平台如何不推RTMP|不发布RTSP流|不实时录像|不回传GB28181数据时实时快照?
本文介绍了一种在Android平台上实现实时截图快照的方法,尤其适用于无需依赖系统接口的情况,如在RTMP推送、RTSP服务或GB28181设备接入等场景下进行截图。通过底层模块(libSmartPublisher.so)实现了截图功能,封装了`SnapShotImpl.java`类来管理截图流程。此外,提供了关键代码片段展示初始化SDK实例、执行截图、以及在Activity销毁时释放资源的过程。此方案还考虑到了快照数据的灵活处理需求,符合GB/T28181-2022的技术规范。对于寻求更灵活快照机制的开发者来说,这是一个值得参考的设计思路。
|
27天前
|
存储 大数据 数据库
Android经典面试题之Intent传递数据大小为什么限制是1M?
在 Android 中,使用 Intent 传递数据时存在约 1MB 的大小限制,这是由于 Binder 机制的事务缓冲区限制、Intent 的设计初衷以及内存消耗和性能问题所致。推荐使用文件存储、SharedPreferences、数据库存储或 ContentProvider 等方式传递大数据。
41 0
|
3月前
|
存储 安全 API
Android经典实战之存储方案对比:SharedPreferences vs MMKV vs DataStore
本文介绍了 Android 开发中常用的键值对存储方案,包括 SharedPreferences、MMKV 和 DataStore,并对比了它们在性能、并发处理、易用性和稳定性上的特点。通过实际代码示例,帮助开发者根据项目需求选择最适合的存储方案,提升应用性能和用户体验。
82 1
|
3月前
|
JSON Java Android开发
Android 开发者必备秘籍:轻松攻克 JSON 格式数据解析难题,让你的应用更出色!
【8月更文挑战第18天】在Android开发中,解析JSON数据至关重要。JSON以其简洁和易读成为首选的数据交换格式。开发者可通过多种途径解析JSON,如使用内置的`JSONObject`和`JSONArray`类直接操作数据,或借助Google提供的Gson库将JSON自动映射为Java对象。无论哪种方法,正确解析JSON都是实现高效应用的关键,能帮助开发者处理网络请求返回的数据,并将其展示给用户,从而提升应用的功能性和用户体验。
81 1
|
3月前
|
编解码 网络协议 前端开发
如何实现Android平台GB28181设备接入模块按需打开摄像头并回传数据
后台采集摄像头,如果想再进一步扩展,可以把android平台gb28181的camera2 demo,都移植过来,实现功能更强大的国标设备侧,这里主要是展示,收到国标平台侧的回传请求后,才打开摄像头,才开始编码打包,最大限度的减少资源的占用
|
3月前
|
编解码 网络协议 Android开发
Android平台GB28181设备接入模块实现后台service按需回传摄像头数据到国标平台侧
我们在做Android平台GB28181设备对接模块的时候,遇到这样的技术需求,开发者希望能以后台服务的形式运行程序,国标平台侧没有视频回传请求的时候,仅保持信令链接,有发起视频回传请求或语音广播时,打开摄像头,并实时回传音视频数据或接收处理国标平台侧发过来的语音广播数据。
|
3月前
|
算法 数据处理 开发工具
Android平台RTSP|RTMP播放器如何回调YUV或RGB数据
在开发Android平台上的RTSP或RTMP播放器时,开发者不仅追求低延迟播放,还希望获取解码后的视频数据(如YUV或RGB格式),以便进行视觉算法分析。使用大牛直播SDK中的SmartPlayer,可在确保播放流畅的同时,通过设置外部渲染器(`SmartPlayerSetExternalRender`)来高效地回调原始视频数据。例如,对于RGBA数据,需实现`NTExternalRender`接口,并重写相关方法以处理数据和尺寸变化。同样地,对于I420(YUV)数据,也需要相应地实现接口以满足需求。这种方式使得开发者能在不影响常规播放功能的情况下,进行定制化的视频处理任务。
|
3月前
|
存储 缓存 Java
Android项目架构设计问题之优化业务接口数据的加载效率如何解决
Android项目架构设计问题之优化业务接口数据的加载效率如何解决
44 0
|
6月前
|
存储 算法 安全
AVB数据解析:Android verified boot 2.0 vbmeta 数据结构解析
AVB数据解析:Android verified boot 2.0 vbmeta 数据结构解析
599 0
|
存储 Android开发
【Android 逆向】函数拦截 ( GOT 表数据结构分析 | 函数根据 GOT 表进行跳转的流程 )
【Android 逆向】函数拦截 ( GOT 表数据结构分析 | 函数根据 GOT 表进行跳转的流程 )
156 0
【Android 逆向】函数拦截 ( GOT 表数据结构分析 | 函数根据 GOT 表进行跳转的流程 )