您的位置:首页 > 移动开发 > Android开发

Android数据篇

2015-06-17 17:42 375 查看
Android提供了多种方式(XML文件方式、文件方式、数据库方式等)进行数据的存储。开发者可以根据数据类型和设计的需要,选择适当的存储方式进行数据存储。

1.XML文件管理

XML文件更多的是用来维护应用或系统的配置文件。在Android中,goole提供了SharedPreferences这个轻型的存储类作为XML文件存储的上层接口,其本质上就是<ket, value>值对。

根据配置信息是否对其他应用开放,SharedPreferences提供了MODE_PRIVATE.、MODE_WORLD_READABLE两种权限。SharedPreferences的操作分为获取配置信息和存储配置信息两种方式。下面是获取配置信息的方法:

SharedPreferences settings=getSharedPreferences(PREFS_NAME,MODE_PRIVATE);

boolean silent=settings.getBoolean("silentMode", false);

存储配置信息和获取配置信息略有不同,下面是存储配置信息的方法:

SharedPreference settings=getShatedPreferences(PREFS_NAME, MODE_PRIVATE);

SharedPreference.Editor editor=settings.edit(); //获得编辑器

editor.putBoolean("silentMode", mSilentMode);

editor.commit(); //提交

如果希望配置信息对其他应用开发,在设置权限时,可使用MODE_WORLD_READABLE。在其他应用希望获取相应的配置信息时,必须先获取相应的上下文,方法如下:

context=createPackageContext("com.miaozl.text", Context.CONTEXT_IGNORE_SECURITY);

if(context != null){

SharedPreference settings=context.getSharedPreference(PREFS_NAME,Context.MODE_WORLD_READABLE);

mTest=settings.getString("text", null);

}

需要说明的是,在PreferenceActivity中内置了对SharedPreferences的支持。

如果希望ListPreference保存或查看当前的选择,可以调用的ListPreferences方法如下:

public void setValue(String value) //对应“android:entries”属性的值

public void setValueIndex(int index) //对应“android:entryValues”属性的值

public String getValue()

其他的Preference的操作方法类似于ListPreference。

2.内部文件管理

对于二进制数据,Android提供了内部存储的方式,开发者可以将数据存储在应用的私有空间中,避免其他程序的访问,内部存储的数据会在应用卸载时删除。

内部存储的实现非常简单,其权限包括MODE_PRIVATE、MODE_APPEND、MODE_WORLD_READABLE、MODE_WORLD_WRITEABLE等。

内部存储所在目录为\data\data\com.company.packagename\files。如果文件名为wors,其内部存储的目录为\data\data\com.android.mms\files\words。

(1)写入数据

写入字符串数据的方法:

FileOutputStream out=context.openFileOutput(file,Context.MODE_WORLD_WRITEABLE);

out.write(captureArray.toString().getBytes());

out.close();

写入结构体数据的方法:

private static void writeConfiguration(Context context, LocaleConfiguration configuration){

DataOutputStream out = null;

out=new DataOutputStream(context.openFileOutput(PREFERENCES, MODE_PRIVATE));

out.writeUTF(configuration.locale);

out.writeInt(configuration.mcc);

out.writeInt(configuration.mnc);

out.flush();

}

(2)读取数据

读取字符串数据的方法:

StringBuilder sb=new StringBuilder();

FileInputStream words=context.openFileInput("word");

int c;

while((c=words.read()) != -1){

if(c=='\r' || c=='\n'){

String word=sb.toString().trim();

if(word.length() > 0){

mWord.add(word);

}

sb.setLength(0);

}else{

sb.append((char)c);

}

}

words.close();

mWordCount=mWords.size();

读取数据结构数据的方法:

private static void readConfiguration(Context context, LocaleConfiguration configuration){

DataInputStream in=null;

in=new DataInputStream(context.openFileInput(PREFERENCES));

configuration.locale=in,readUTF();

configuration.mcc=in.readInt();

configuration.mnc=in.readInt();

in.close();

对于应用携带的静态数据,可以放置在应用的assets目录或res、raw目录下。

对于assets目录下的静态数据,存在单个文件最大仅支持1MB的局限,读取方式:InputStream is=getAssets().open("read_asset.txt");

对于res、raw目录下的静态数据,读取方式:InputStream.inputStream=resources.openRawResource(R.raw.definitions);

Android还对创建缓存提供了支持,通过getCacheDir()可以获取应用的缓存路径。在系统可用空间不足时,Android会清空缓存,但对于开发者而言,不应维护过多的缓存。和内部存储一样,在应用卸载时,会清空并删除缓存目录。

3.外部文件管理

为了便于进行媒体文件的扫描,Android为媒体文件设置了特定目录,目前Android支持DIRECTORY_MUSIC、DIRECTORY_PODCASTS、DIRECTORY_RINGTONES、DIRECTORY_ALARMS、DIRECTORY_NOTIFICATIONS、DIRECTORY_PICTURES、DORECTORY_MOVIES、DIRECTORY_DOWNLOADS等目录。

Android开始支持在SD卡上的应用私有目录,通过getExtenalFilesDir()可以获取具体路径。该具体路径依赖应用的包名,如com.miaozl.helle,其SD卡上的应用私有目录为\mnt\sdcard\Android\data\com.miaozl.hello\files\。下面是获取图片路径的方法:File path=getExternalFilesDir(Environment.DIRECTORY_PICTURES)。

如果希望存储在SD上的公共目录下,则可通过getExternalStoragePublicDirectory可以获得公共目录,但需要注意,公共目录的具体路径视需要存储的文件的类型而定。下面是获取公共目录的方法:

String sdroot=Environment.getExternalStorageDirectory().getAbsolutePath();

String dwndir=Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_DOWNLOADS).getAbsolutePath();

SD上的应用私有目录和内部存储一样,在应用卸载时,将会被清空并删除。

如果应用需要的缓存较大,也可以在SD卡上建立缓存目录,通过getExternalCacheDir()可以获取应用在SD卡上的缓存路径。

在使用SD卡目录时,需要注意SD卡是否挂载,可通过Environment.getExternalStorageState()方法进行判断。如果返回值为Environment.MEDIA_MOUNTED,表示SD卡处于挂载状态,可以放心使用。

4.数据库管理

通过数据库的方式可以存储复杂的数据,也可以方便对数据的操作,因此数据库存储在Android中非常有用。目前,Android采用SQLite3数据库。SQLite3数据库是一种适合嵌入式平台的轻量级数据库。但是开源版本的SQLite3没有对数据进行加密保护,因此存储敏感数据是一个十分头疼的问题。好在SQLite3在框架层提供了加密算法的接口,有需要的开发者可以自行添加相关的加密算法。

Android提供了两种SQLite的实现方法,一种是基于Android封装接口来实现的,适合对数据库要求不高或对SQLite不熟悉的开发者;另一种是基于原生SQLite的方法来实现的,可以完全发挥出SQLite的能力,性能稍好,但对SQLite的理解要求较高。至于采用何种实现方法,开发者可以根据应用场和自己对SQLite的理解程度自行把握。

对于数据读取频繁的场景,必须考虑SQLite的性能,在Android平台上,使用原始SQL语句的执行效率要比封装过的ContentProvider高;对于一次性进行多项处理的场景,应考虑通过事务处理的方式进行批量处理。

(1)Android封装接口

考虑到数据库的操作很频繁,在Android中提供了封装类,即SQLiteOpenHelper,通过集成SQLiteOpenHelper,开发者可以很容易地设计和操作数据库。需要注意的是,封装会使Android的性能降低。

在继承SQLiteOpenHelper时,必须实现onCreate和onUpgrade方法。下面是通过Android封装接口设计数据库的一般步骤:定义数据库名、数据库版本号、数据表名。实现onCreate和onUpgrade方法。实现插入、更新、删除和查询方法。

实现onCreate方法:

public void onCreate(SQLiteDatabase db){

db.execSQL("CREATE TABLE "+NOTES_TABLE_NAME+"(" + NoteColumns._ID+ " INTEGER PRIMARY KEY,"+NoteColumns.TITLE+" TEXT,"

+NoteColumns.NOTE+" TEXT,"+NoteColumns.CREATED_DATE+" INTEGER," +NoteColumns.MODIFIED_DATE+" INTEGER"+");");

}

实现onUpgrade方法:

public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion){

db.execSQL("DROP TABLE IF EXISTS notes");

onCreate(db);

}

事务处理的相关方法:

public void begintransaction()

public void beginTransactionWithListener(SQLiteTransactionListener transactionListener)

public void endTransaction()

public boolean inTreansaction()

public void setTransactionSuccessful()

(2)原生方法处理

采用raw方法来操作SQLite数据库,可以减少代码和提高处理效率,但必须做好SQL语句异常处理。

SQLiteDatabase db;

String args[]={id};

ContextValue cv=new ContextValues();

cv.put("miaozl", id);

Cursor c=db.rawQuery("SELECT * FROM table WHERE miaozl =?", args); //执行本地SQL语句

if(c.getCount() !=0){

ContextValues cv=new ContextValues();

cv.put("miaozl","cwj");

db.insert("table", "miaozl", cv); //插入数据

String args[]={id};

ContextValues cv2=new ContextValues();

cv2.put("miaozl", id);

db.delete("table", "miaozl=?", args);

5.数据处理

进行Android开发,尤其是开发涉及网络的应用时,对数据进行处理是个无法回避的问题。Android采用的是Java数据结构,且基本支持所有的Java数据结构。在本节中,除了讨论基本的Java数据类型外,还将讨论正则表达式、I/O管理、流、JSON等,这些内容对从C/C++迁移过来的开发者非常有用。Java数据结构之间的关系如下图:



Collection和Map是最基本的数据结构。

所有实现Collection接口的类都必须提供两个标准的构造函数:一个是无参数的构造函数,用于创建空白的Collection;另一个是Collection作为参数的构造函数,用于创建一个新的Collection,这个新的Collecntion与传入的Collection有相同的元素。第二个构造函数允许用户复制一个Collection。

遍历Collection可以通过iterator方法进行,该方法返回一个迭代因子,利用该迭代因子可逐一访问Collection中的元素。典型用法如下:

Iterator it=collection.iterator(); //获得一个迭代因子

while(it.hasNext()){

Object obj=it.next(); //得到下一个元素

}

由Collection接口派生的两个接口是List和Set。

(1)Set类

Set类保持的对象不可重复,Android目前支持的Set类主要包括HashSet、TreeSet、LinkedHashSet等。

1)HashSet

HashSet实现了Set接口和内置哈希表,它不保证集合的迭代顺序。

向HashSet中添加集合项的方法:

public void addChild(BuildStep child){

if(children == null){

children=new HashSet<BuildStep>();

}

children.add(child)

}

HashSet还支持清空、克隆、移除等操作,另外,HashSet还支持从资源文件中加载数组,具体如下:

HashSet<String>defaultCorpora=new HashSet<String>();

try{

String[] corpora=mContext.getResource().getStringArray(res);

for(String corpus : corpora){

defaultCorpora.add(corpus);

}

return defaultCorpora;

}

HashSet不支持线程安全,其集合项可以为null。

2)TreeSet

TreeSet是SortedSet接口的唯一实现类,TreeSet可以确保集合元素处于排列状态。它是J2EE中唯一可实现自动排序的类,TreeSet支持两种排序方式,自然排序和定制排序,其中自然排序为默认的排序方式。向TreeSet中加入的应该是同一个类的对象。向TreeSet中添加集合项的方法:

TreeSet smallSet=new TreeSet(); //自然排序

for(int i=0; i<50;i++){

smallSet.add(objArray[i]);

}

对于定制排序的情况,需要先构建一个Comparator类型的排序器,方法如下:

public class MyComparator<T> implements Comparator<T>{

public int compare(T arg0, Targ1){

if(arg0.equal(arg1)){

return 0;

}

return ((Comparable<T> arg0).compare(arg1)*-1;

}

}

TreeSet<String> treeSet=new TreeSet<String>(myConparator);

treeSet.add("A");

3)LinkedHashSet

和HashSet相比,LinkedHashSet中的数据严格按照插入的顺序存放,新增的数据放置在集合的末尾。LinkedHashSet内部通过LinkedHashMap实现,添加集合项的方法:

LinkedHashSet<String>ids = new LinkedHashSet<String>();

ids.add(TimeZone.getDefault().getID());

另外LinkedHashSet还支持清空、复制、移除等操作。具体方法如下:

void clear();

Object clone();

boolean remove(Object object);

LinkedHashSet还支持遍历操作,方法如下:

LinkedHashSet<String>addresses=new LinkedHashSet<String>;

Iterator<String> addressIterator=addresses.iterator();

while(addressIterator.hasNext()){

String assress=addressIterator.next();

addressIterator.remove();

}

LinkedHashSet在迭代访问Set中的全部元素时,性能比HashSet好,但是在进行插入曹组时,性能方面稍逊于HashSet。

(2)Map类

Map类保存着<key,value>的对应关系。Android目前支持的Map类主要有HashMap、LinkedHashMap和WeakHashMap等。

1)HashMap

HashMap的实现是基于哈希表的,创建HashMap非常简单,方法:Map<String, Boolean>entries=new HashMap<String, Boolean>();

如果希望在创建HashMap对象时声明HashMap的容量,方法:Map<AttributedCharcterIterator.Attribute, List<Range>>attributeMap=new HashMap<Attribute,List<Range>>(11);

考虑到迭代时间和HashMap的容量和大小成比例,HashMap的初始容量不易设置太大,毕竟当哈希表中的键值对数量超过HashMap的加载因子与HashMap的容量的乘积时,HashMap会自动扩展容量,不会出现容量不够的问题。在默认情况下,HashMap的加载因子为0.75。在创建HashMap对象时,可以自定义HashMap的加载因子。

向HashMap中添加键值对的方法:

private final Map<AudioStream, Integer> mStream;

mStreams=new HashMap<AudioStream, Integer>();

if(!mStreams.containsKey(stream)){ //判断key为“stream”的映射是否存在

int socket=stream.dup();

mStreams.put(stream,socket);

}

获得HashMap中键值对信息的方法:

private final HashMap<String, Integer> mMap;

Set<Entry<String, Integer>>mEntries=mMap.entrySet();

for(Entry<String, Integer>entry:mEntries){

Integer freg=entry.getValue();

db.delete(AUTODICT_TABLE_NAME, COLUMN_WORD+ "=? AND " + COLUMN_LOCALE+"=?", new String[]{entry.getKey(), mLocale});

if(freq!=null){

db.insert(AUTODICY_TABLE_NAME, null, getContentValues(entry.getKey(),freq, mLocale));

}

}

HashMap中的另外几个重要方法:

public boolean containsValue(Object value)

public int size()

public boolean isEmpty()

V get(Object key)

2)LinkedHasMap

与HashMap相比,LinkedHashMap维护的是一个具有双重链表的HashMap,LinkedHashMap输出时其键值对是有顺序的,而HashMap输出时其键值对是随机的。对于键值对比较复杂而又要求效率的情况下,最好使用LinkedHashMap。LinkedHashMap支持两种排序方式,一种是插入排序,最近插入的在链表尾部;一种是使用排序,最近使用的会移至链表尾部。

private static final float DEFAULT_LOAD_FACTOR=.75F;

private final Map<String, AddressCacheEntry> map;

map=new LinkedHashMap<String, AddressCacheEntry>(0, DEFAULT_LOAD_FACTOR, true); //true表示使用排序,false表示插入排序

synchronized(map){

map.put(hostname, new AddressCacheEntry(addresses, expiryNanos));

}

注意,LinkedHashMap并非线程安全的,如果确需实现线程安全,那么可以使用如下方法:

Map<String, String>map=Colleations.synchronizedMap(new LinkedHashMap<String, String>)

3)WeakHashMap

WeakHashMap和普通HashMap的不同之处在于其包含的键值对的Key为弱引用,当Key不再被其他对象引用时,相应的键值对可能会被垃圾回收器随时释放。

WeakHashMap对象的创建方法:private final WeakHashMap<String, Package>mPackages=new WeakHashMap<String, Package>();

WeakHashMap具有的方法和HashMap类似,两者都继承于AbstractMap的。

(3)list类

List类存储对象可以重复。Android目前支持的List类主要有ArrayList、LinkedList等。

1)ArrayList

ArrayList是Android中最常用的集合类,本质上是可变数据的实现,允许包括null在内的所有元素。由于插入数据会涉及数组元素的移动,因此所有ArrayList进行数据索引较快,而插入数据较慢。

ArrayList<THread>list =new ArrayList<Thread>();

for(Node p=tail; p!=null; p=p.prev){

Thead t=p.thread;

if(t!= null)

list.add(t)

}

ArrayList也是非线程安全的,和ArrayList类似的一个工具是Vector,所不同的是Vector是线程安全的,其性能比ArrayList稍差。Stack继承自Vector,是一个后进先出的栈。

2)LinkedList

LinkedList利用双向链表实现存储,其插入数据较快,索引数据较慢。

(4)流类

Android对流的支持和Java类似,主要有BufferedInputStream、BufferedOutputStream、BufferedReader、BufferedWriter、ByteArrayInputStream、ByteArrayOutputStream、FileInputStream、FileOutputStream、StringReader、StringWriter等。

1)缓冲流

考虑到硬盘存取的速度远低于内存中数据存取速度,为了减小对硬盘的存取,在内存中建立了缓存区,这样可以提高存取的效率。这就是BufferedInputStream、BufferedOutputStream优于InputStream、OutputStream之处。

BufferedInputStream和BufferedOutputStream并非改变InputStream和OutputStream等行为,具体的读写仍有InputStream和OutputStream负责。

下面是BufferedOutputStream的一个示例:

try{

BufferedOutputStream out=new BufferedOutputStream(new FileOutputStream("\sdcard\a.text"));

for(int i=0; i<200;i++)

out.write(i);

out.flush(); //写入目标对象

}

2)字节流

在创建实例时ByteArrayInputStream和ByteArrayOutputStream会构建一个byte类型的数组作为缓冲区,以适合传输多个变量的场景。下面是一个示例:

CopyOnWriteArrayList q=populatedArray(SIZE);

ByteArrayOutputStream bout=new ByteArrayOutputStream(10000);

ObjectOutputStream out=new ObjectOutputStream(new BufferedOutputStream(bout));

out.writeObject(q);

out.close();

ByteArrayInputStream bin=new ByteArrayInputStream(bout.toByteArray());

ObjectArrayInputStream in=new ObjectInputStream(new BufferedInputStream(bin));

CopyOnWriteArrayList r=(CopyOnWriteArrayList)in.readObject();

3)文件流

FileInputStream和FileOutputStream专门用于文件读取,以字节为单位进行流处理,与编码无关,所以不会存在乱码问题。FileReader和FileWriter则以字符为单位进行流处理。下面是一个文件复制的实现:

File inFile =new File("source.jpg");

File outFile=new File("dest.jpg");

FileInputStream inStream=new FileInputStream(inFile);

FileOutputStream outStream=new FileOutputStream(outFile);

byte[] inOutb=new byte[inStream.available()];

inStream.read(inOutb); //读入流,保存在byte数组

outStream.write(inOutb); //写入流,保存在文件dest.jpg中

inStream.close();

outStream.close();

byte数组的最大存储容量为64MB,当一个文件超过64MB时,需要分多个流进行读写。另外,当在两个不同的线程间进行文件读写时,同步会变得比较困难,这时可以考虑运用管道,即PipedInputStream、PipedOutputStream等。

当程序对读写的速率要求较高时,FileChannel会是比FileInputStream/FileOutputStream更好的选择,FileChannel是线程安全的。

当需求对内容进行分析时,就需要用到FileReader和FileWriter,他们经常和BufferedReader、BufferedWrite组合使用。FileReader和BufferedReader组合使用的示例如下:

BufferedReader input = new BufferedReader(new FileReader(layoutFile));

String line;

while((line=input.readLine())!=null){

}

FileWriter和BufferedWriter组合使用的示例如下:

BufferedWriter out=null;

try{

out=new BufferedWriter(new FileWriter(DOCK_PIN_PATH));

int pin=(int)Math.floor(Math,random()*10000);

mDockPin=String.format("%04d",pin);

out.write(mDockPin);

return true;

}

4)字符串流

StringReader和StringWriter是专门针对字符串设计得。StringReader多用于XML的解析的场景。StringReader的用法如下:

private static final String XMLFILE=”<feed xmlns='http://www.w3.org/2005/Atom‘><name><id>bob</id></name>"

+"<entry1><id year=\"2009\">james</id></entry1><entry2 year=\"2000\"><id>jim</id></entry2>"

+"<name><id>tom</id></name><name><id>brett</id></name></feed>";

SAXParserFactory spfactory=SAXPareserFactory.newInstance();

SAXPareser saxPareser=spfactory.newSAXPareser();

XMLReader xmlReader=saxPareser.getXMLReader();

xmlReader.setContentHandle(root.getContentHander());

InputSource source=new InputSource(new StringReader(XMLFILE));

xmlReader.parse(source);

StringWriter的用法如下:

Therowable thrown=r.getThrown();

StringWriter sw=new StringWriter();

PrintWriter pw=new PrinrWriter(sw);

sw.write(r.getMessage());

sw.write("\n");

throw.printStackTrace(pw);

pw.flush();

return sw.toString();

5)正则表达式

在Android中使用正则表达式非常简单,相关的类主要有Pattern、Matcher等。对读者来说,最重要的是了解正则表达式的语法规则。下面是几个常用场景的实现

String
str=“ceponline@yahoo.com.cn";

Pattern pattern=Pattern.compile("[\\w\\.\\-]+@([\\w\\-]+\\.)+[\\w\\-]+",Pattern.CASE_INSENSITIVE);

Matcher matcher = pattern.matcher(str);

替换字符的方式实现:

Matcher m=Pattern.compile("[\t\n],").matcher(string);

string = m.replaceAll(".").raplace('\n', ' ').replace('\n',' ');

查找字符串的实现:

private static final Pattern sRepeatedRangePattern=Pattern.compile("Resource entry (.+) already has bag item (.+)\\.");

matcher=sRepeatedRangePattern.matcher(message);

if(matcher.find()){

String property=matcher,group(2);

return findRange(file, line,property, null);

}

(6)I/O管理

除了流类型的I/O管理和文件管理外,Android还提供了MemoryFile、FileChannel进行I/O管理。MemoryFile是对Ashmem驱动的封装器,而Ashmem本质上是基于共享内存的。在dev目录下对应的设备为\dev\ashmem。相比于传统的内存分配机制,如malloc,Ashmem的好处是提供了辅助内核内存回收算法的pin\unpin机制,使通过MemoryFile进行I/O操作可以在很大程度上提高效率。

FileChannel是MMAP的一个上层封装。利用FilehChannel可以更高效地读写文件,而且FileChannel是线程安全的。

1)MemoryFile

创建一个MemoryFile对象即可在共享内存上分配一块区域。通过MemoryFile对象读写数据的方式有流、字节两种。

MemoryFile在断言、SQLite等多个领域的读写得到了应用。

2)FileChannel

开发者可以从FileInputStream、FileOutputStream、RandomAccessFile等的对象中获得FileChannel对象,FileChannel是线程安全的。从FileInputStream中得到FileChannel的方法如下:

FileChannel fc=new FileInputStream(new File("temp.tmp")).getChannel();

IntBuffer ib=fc.map(FileChannel.MapMode.READ_ONLY,0,fc.size()).asIntBuffer();

while(ib.hasRemaining())

ib.get();

fc.close();

从FileOutputStream、RandomAccessFile等对象获得FileChannel对象的方法和FileInputStream类似。另外在FileChannel中读写数据都是基于缓冲进行的,读取数据的方法如下:

FileChannel fc=new FileInputStream("demo.tex").getChannel();

ByteBuffer buff=ByteBuffer.allocate(BSIZE);

buff.clear();

fc.read(buff);

buff.flip();

在FileChannel中写入数据的方法如下:

FileOutputStream fileOutputStream=new FileOutputStream(tmpFile);

FileChannel fileChannel=fileOutputStream.getChannel();

ByteBuffer byteBuffer=ByteBuffer.allocatedirect(BUFFER_LENGTH);

byteBuffer.clear(); //向byteBuffer中写入数据

fileChannel.write(byteBuffer);

fielChannel.Close();

fileOutputStream.close();

FileChannel还支持在两个通道间传输,方法如下:

FileChannel in=new FileInputStream("source.txt").getChannel();

FileChannel out=new FileOutputStream("dest.txt").getChannel();

in.transferTo(0, in.size(), out);

需要说明的是,FileChannel.MapMode支持3中类型的映射模式,即READ_ONLY、PRIVATE和READ_WRITE。

(7)JSON实现

在网络编程中,数据的传递非常重要,JSON(JavaScript Object Notation)和XML各有优点,XML扩展性好,JSON语法简单。JSON支持两种数据结构,一种是数组,即值得有序列表;另一种是对象,即键值对的集合。

JSON中有一些特殊字符需要注意,如单引号、正斜杠、反斜杠、换行符等。

Android对JSON的支持比较全面,以前Android通过org.json包提供了对JSON的支持,但功能不够强大,使用起来十分不便。目前,Android引入了JsonWrite、JsonReader两个类,极大地简化了操作。

1)写入数据

JsonWrite本质上是一种输出流,在写入对象数据时,必须以beginObject方法开始,以endObject方法结束;在写入数组数据时,必须以beginArray方法开始,以endArray方法结束。

JsonWriter不支持线程安全。

2)读取数据

JsonReader本质上是一种输入流,在读取对象数据时,必须以beginObject方法开始,以endObject方法结束;读取数组数据时,必须以beginArray方法开始,以endArray方法结束。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: