随笔 - 312, 文章 - 14, 评论 - 1393, 引用 - 0
数据加载中……

《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保存尺寸很大的数据。如果读者要存取更




Android开发完全讲义(第2版)(本书版权已输出到台湾)

http://product.dangdang.com/product.aspx?product_id=22741502



Android高薪之路:Android程序员面试宝典 http://book.360buy.com/10970314.html


新浪微博:http://t.sina.com.cn/androidguy   昵称:李宁_Lining

posted on 2010-09-08 09:49 银河使者 阅读(3914) 评论(5)  编辑  收藏 所属分类: java 原创移动(mobile) 图书Android/OPhone

评论

# re: 《Android/OPhone开发完全讲义》连载(7):使用SharedPreferences存取复杂数据[未登录]  回复  更多评论   

PreferenceScreenExt 代码:




package asai.cn.seekbardemo;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;

import android.app.Dialog;
import android.content.Context;
import android.content.DialogInterface;
import android.content.SharedPreferences;
import android.preference.Preference;
import android.preference.PreferenceGroup;
import android.util.AttributeSet;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.view.View.OnClickListener;
import android.widget.AdapterView;
import android.widget.ListView;
import android.widget.RelativeLayout;
import android.widget.SimpleAdapter;
import android.widget.TextView;
import android.widget.AdapterView.OnItemClickListener;

public class PreferenceScreenExt extends PreferenceGroup implements
OnItemClickListener, DialogInterface.OnDismissListener {

private Dialog dialog;
private TextView title, summary;
private SharedPreferences share;
private RelativeLayout area;
private ListView listView;
List<Preference> list;

private List<HashMap<String, String>> listStr;
private CharSequence[] mEntries;
private String mValue;

public PreferenceScreenExt(Context context, AttributeSet attrs) {
this(context, attrs, android.R.attr.preferenceScreenStyle);
// TODO Auto-generated constructor stub
}

public PreferenceScreenExt(Context context, AttributeSet attrs, int defStyle) {
super(context, attrs, android.R.attr.preferenceScreenStyle);
// TODO Auto-generated constructor stub
int resouceId = attrs.getAttributeResourceValue(null, "Entries", 0);
if (resouceId > 0) {
mEntries = getContext().getResources().getTextArray(resouceId);
}
}

@Override
protected View onCreateView(ViewGroup parent) {
// TODO Auto-generated method stu
View view = LayoutInflater.from(getContext()).inflate(
R.layout.preference_screen, null);
area = (RelativeLayout) view.findViewById(R.id.area);
share = getPreferenceManager().getSharedPreferences();
title = (TextView) view.findViewById(R.id.title);
summary = (TextView) view.findViewById(R.id.summary);
title.setText(getTitle());
summary.setText(share.getString(getKey(), getSummary() == null ? ""
: getSummary().toString()));
area.setOnClickListener(new OnClickListener() {

@Override
public void onClick(View v) {
// TODO Auto-generated method stub
showDialog();
}
});
return view;
}

public void bindView(ListView listview) {
int length = mEntries.length;
int i = 0;
listStr = new ArrayList<HashMap<String, String>>();
for (i = 0; i < length; i++) {
HashMap<String, String> map = new HashMap<String, String>();
map.put("keyname", mEntries[i].toString());
listStr.add(map);
}
SimpleAdapter simple = new SimpleAdapter(getContext(), listStr,
R.layout.dialog_view, new String[] { "keyname" },
new int[] { R.id.text });
listview.setAdapter(simple);
listview.setOnItemClickListener(this);
}

public void showDialog() {
listView = new ListView(getContext());
bindView(listView);
dialog = new Dialog(getContext(), android.R.style.Theme_NoTitleBar);
dialog.setContentView(listView);
dialog.setOnDismissListener(this);
dialog.show();
}

@Override
public void onItemClick(AdapterView<?> parent, View view, int position,
long id) {
// TODO Auto-generated method stub
mValue = listStr.get(position).get("keyname").toString();
SharedPreferences.Editor editor = getEditor();
editor.putString(getKey(), mValue);
editor.commit();
dialog.dismiss();
}

@Override
public void onDismiss(DialogInterface dialog) {
// TODO Auto-generated method stub
summary.setText(mValue);
}
}
2010-09-25 14:35 | terry

# re: 《Android/OPhone开发完全讲义》连载(7):使用SharedPreferences存取复杂数据[未登录]  回复  更多评论   

对应的XML


preference_screen.xml

<RelativeLayout android:id="@+id/area" android:gravity="center_vertical"
android:layout_marginTop="5px" android:clickable="true"
xmlns:android="http://schemas.android.com/apk/res/android"
android:background="@drawable/row_bg" android:layout_width="fill_parent"
android:layout_height="wrap_content">

<TextView android:id="@+id/title" android:layout_marginLeft="20dp"
android:textAppearance="?android:attr/textAppearanceLarge"
android:textSize="35sp" android:layout_width="wrap_content"
android:layout_height="wrap_content">
</TextView>
<TextView android:id="@+id/summary"
android:layout_marginRight="20dp" android:textSize="35sp"
android:textAppearance="?android:attr/textAppearanceLarge"
android:layout_alignParentRight="true" android:layout_width="wrap_content"
android:layout_height="wrap_content">
</TextView>
</RelativeLayout>
2010-09-25 14:35 | terry

# re: 《Android/OPhone开发完全讲义》连载(7):使用SharedPreferences存取复杂数据[未登录]  回复  更多评论   

dialog_view.xml


<LinearLayout android:layout_width="fill_parent"
android:background="@drawable/row_bg" xmlns:android="http://schemas.android.com/apk/res/android"
android:orientation="vertical" android:gravity="center"
android:layout_height="fill_parent">


<TextView android:id="@+id/text" android:layout_marginLeft="20dp"
android:textAppearance="?android:attr/textAppearanceLarge"
android:textSize="35sp" android:layout_width="wrap_content"
android:layout_height="wrap_content">
</TextView>


</LinearLayout>
2010-09-25 14:36 | terry

# re: 《Android/OPhone开发完全讲义》连载(7):使用SharedPreferences存取复杂数据[未登录]  回复  更多评论   

随便测试的ActivityGroup:


package asai.cn.seekbardemo;

import android.app.ActivityGroup;
import android.app.LocalActivityManager;
import android.content.Intent;
import android.os.Bundle;
import android.view.View;
import android.view.Window;
import android.view.View.OnClickListener;
import android.widget.Button;
import android.widget.LinearLayout;

public class main extends ActivityGroup implements OnClickListener {

private LocalActivityManager lm;
private LinearLayout layout;
private Button btn, btn2;

@Override
protected void onCreate(Bundle savedInstanceState) {
// TODO Auto-generated method stub
super.onCreate(savedInstanceState);
setContentView(R.layout.group);
lm = getLocalActivityManager();

layout = (LinearLayout) findViewById(R.id.layout);
btn = (Button) findViewById(R.id.Button01);
btn2 = (Button) findViewById(R.id.Button02);

btn.setOnClickListener(this);
btn2.setOnClickListener(this);
Intent intent = new Intent(this, seekBarDemo.class);
intent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP);
Window w = lm.startActivity("test", intent);
View v = w.getDecorView();
layout.removeAllViews();
layout.addView(v);
layout.invalidate();

}

@Override
public void onClick(View v) {
// TODO Auto-generated method stub
switch (v.getId()) {
case R.id.Button01:
Intent intent = new Intent(this, seekBarDemo.class);
intent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP);
Window w = lm.startActivity("test", intent);
View view = w.getDecorView();
layout.removeAllViews();
layout.addView(view);
break;
case R.id.Button02:
Intent in = new Intent(this, test.class);
in.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP);
Window win = lm.startActivity("ww", in);
View vw = win.getDecorView();
layout.removeAllViews();
layout.addView(vw);
break;
default:
break;
}
}
}
2010-09-25 14:37 | terry

# re: 《Android/OPhone开发完全讲义》连载(7):使用SharedPreferences存取复杂数据[未登录]  回复  更多评论   

还少了个XML配置:
<asai.cn.seekbardemo.PreferenceScreenExt
Entries="@array/country" android:title="收音区域" android:summary="美国"
android:key="eeg">
</asai.cn.seekbardemo.PreferenceScreenExt>


数组:
<string-array name="country">
<item>美国</item>
<item>中国</item>
<item>英国</item>
</string-array>
2010-09-25 14:42 | terry

只有注册用户登录后才能发表评论。


网站导航: