由于最近的项目中需要在百度地图中根据不同区域来颜色渲染,如下图的效果。想了一下,如果每次加载地图时都要去进行联网并从百度地图的接口中返回这些地区的边界经纬度再进行测绘,那不仅会造成流量的损耗,在性能上也将大打折扣,就想着,那就做个进行数据缓存吧,但是又转念一想,这些属于特定数据,基本是不会变的,直接在百度上撸下边界数据后自己渲染地图来得更实在些,在考虑了之后,选择了XML作为数据的保存形式。好了,一般写博客之前我都习惯先废话一下,现在废话结束,进入正题。
,
在Android开发中,XML作为数据保存的方式之一,由于XML文件会随着APK被打包,故而常被使用来保存一些特定且数据量不大的数据。在Android中,主要有以下几种解析XML方式:
SAX解析器:
SAX(Simple API for XML)解析器是一种基于事件的解析器,它的核心是事件处理模式,主要是围绕着事件源以及事件处理器来工作的。当事件源产生事件后,调用事件处理器相应的处理方法,一个事件就可以得到处理。在事件源调用事件处理器中特定方法的时候,还要传递给事件处理器相应事件的状态信息,这样事件处理器才能够根据提供的事件信息来决定自己的行为。
SAX解析器的优点是解析速度快,占用内存少。非常适合在Android移动设备中使用。
DOM解析器:
DOM是基于树形结构的的节点或信息片段的集合,允许开发人员使用DOM API遍历XML树、检索所需数据。分析该结构通常需要加载整个文档和构造树形结构,然后才可以检索和更新节点信息。
由于DOM在内存中以树形结构存放,因此检索和更新效率会更高。但是对于特别大的文档,解析和加载整个文档将会很耗资源。
PULL解析器:
PULL解析器的运行方式和SAX类似,都是基于事件的模式。不同的是,在PULL解析过程中,我们需要自己获取产生的事件然后做相应的操作,而不像SAX那样由处理器触发一种事件的方法,执行我们的代码。PULL解析器小巧轻便,解析速度快,简单易用,非常适合在Android移动设备中使用,Android系统内部在解析各种XML时也是用PULL解析器。
1.将数据保存为XML文件:XMLSaveTool.java
public class XMLSaveTool {
List<HashMap<String,List<List<LatLng>>>>mdatas;//传入的数据源
Context mContext;
public XMLSaveTool(List<HashMap<String,List<List<LatLng>>>>data,Context context) {
this.mContext=context;
this.mdatas=data;
saveDataToXML();
}
private void saveDataToXML(){
try {
File file = new File(Environment.getExternalStorageDirectory(), "CityLine.xml");
Log.e("hjo", "文件路径:"+Environment.getExternalStorageDirectory());
FileOutputStream fos = new FileOutputStream(file,true);//文件以追加的形式保存 去掉true为覆盖保存方式
//获取XmlSerializer对象
XmlPullParserFactory factory = XmlPullParserFactory.newInstance();
org.xmlpull.v1.XmlSerializer xmlSerializer = factory.newSerializer();
//设置输出流对象
xmlSerializer.setOutput(fos, "utf-8");
xmlSerializer.startDocument("utf-8", true);
HashMap<String,List<List<LatLng>>>data;
List<List<LatLng>>listLines;
/*将数据保存为以下格式
* <ListCity>
* <CityName name="">
* <LatLng latitude="" ,longitude=""></LatLng>
* <LatLng latitude="" ,longitude=""></LatLng>
* <LatLng latitude="" ,longitude=""></LatLng>
* .
* .
* .
* <LatLng latitude="" ,longitude=""></LatLng>
* </CityName>
* </ListCity>
*/
xmlSerializer.startTag(null, "ListCity");//最外层
for (int i = 0; i < mdatas.size(); i++) {
data=mdatas.get(i);
xmlSerializer.startTag(null, "CityName");//
for (Entry entry :data.entrySet() ){//只有一个值 进入一次
xmlSerializer.attribute(null, "name", entry.getKey().toString());//以组的形式保存
listLines=data.get(entry.getKey().toString());
for (List<LatLng>LineLL:listLines ) {
for (LatLng ll : LineLL) {
xmlSerializer.startTag(null, "LatLng");
// xmlSerializer.attribute(null, "latitude", ""+ll.latitude);
// xmlSerializer.attribute(null, "longitude", ""+ll.longitude);
String latitude=""+ll.latitude;
String longitude=""+ll.longitude;
xmlSerializer.startTag(null, "latitude");
xmlSerializer.text(latitude);
xmlSerializer.endTag(null, "latitude");
xmlSerializer.startTag(null, "longitude");
xmlSerializer.text(longitude);
xmlSerializer.endTag(null, "longitude");
xmlSerializer.endTag(null, "LatLng");
}
}
}
xmlSerializer.endTag(null, "CityName");
}
xmlSerializer.endTag(null, "ListCity");
} catch (Exception e) {
}
}
}
说明:以上传入的数据源为List<HashMap<String,List<List<LatLng>>>>形式,所以在进行转化保存时有所不一样,你同样可以根据自己的数据形式来进行保存,原理基本一样,可以是一个model,也可以是一个数组。
在进行调用时直接new一个saveDataToXML,并根据参数传入即可。最后得到的数据如下:PS 由于数据量太大,只能截一部分,并且我没有做换行操作,你可以在每个节点结束时加入“\n”进行换行。
2. 好了,数据保存以后,如何进行读取,也就是解析就是接下来要做的事情。解析方式有刚介绍的以上三种,下面采用SAX来进行数据的解析,该方式需要继承DefaultHandler,并重写它的几个方法。
MyXMLHandler.java
<span style="font-size:14px;">public class MyXMLHandler extends DefaultHandler {
private List<HashMap<String, List<List<LatLng>>>>mData;
List<List<LatLng>>data=new ArrayList<List<LatLng>>();
List<LatLng>ListLL=new ArrayList<LatLng>();
HashMap<String, List<List<LatLng>>>hastMap;
double latitude;
double longitude;
String CityName;
private StringBuilder builder=new StringBuilder();
// public List<HashMap<String, List<List<LatLng>>>> getmData() {
// return mData;
// }
public List<HashMap<String, List<List<LatLng>>>> getmData() {
return mData;
}
public void setmData(List<HashMap<String, List<List<LatLng>>>> mData) {
this.mData = mData;
}
@Override
public void startElement(String uri, String localName, String qName,
Attributes attributes) throws SAXException {//读到开始节点时调用 一般这个节点作为初始化操作
if (localName.equals("ListCity")) {
mData=new ArrayList<HashMap<String,List<List<LatLng>>>>();
}else if (localName.equals("CityName")) {
CityName=attributes.getValue(0);
hastMap=new HashMap<String, List<List<LatLng>>>();
data=new ArrayList<List<LatLng>>();
}else if (localName.equals("LatLng")) {
ListLL=new ArrayList<LatLng>();
}else if (localName.equals("name")) {
Log.e("hjo", CityName);
}
builder.setLength(0);//清空
}
@Override
public void characters(char[] ch, int start, int length) throws SAXException { //读取到值时调用
super.characters(ch, start, length);
builder.append(ch, start, length); //将读取的字符数组追加到builder中
}
@Override
public void endElement(String uri, String localName, String qName)
throws SAXException {//读取到结束节点时调用 一般在这个节点进行数据的保存
if (localName.equals("name")) {
// CityName=builder.toString();
}else if (localName.equals("latitude")) {
latitude=Double.valueOf(builder.toString());
} else if (localName.equals("longitude")) {
longitude=Double.valueOf(builder.toString());
LatLng ll=new LatLng(latitude, longitude);
ListLL.add(ll);
}else if (localName.equals("LatLng")) {
data.add(ListLL);
}else if (localName.equals("CityName")) {
hastMap.put(CityName, data);
mData.add(hastMap);
}
else if (localName.equals("ListCity")) {
setmData(mData);
}
}
}</span><span style="font-size:18px;">
</span>
说明:以上的解析要根据你数据里保存的形式来,对于有使用到组来保存的地方,获取值时使用的是attributes.getValue(0); 这里的参数0指的是第一个。
3. 以下是解析时调用 MainActivity.java
<span style="font-size:14px;">public class MainActivity extends ActionBarActivity {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
List<HashMap<String, List<List<LatLng>>>>mData=new ArrayList<HashMap<String,List<List<LatLng>>>>();
AssetManager asset = getAssets();
try {
InputStream input = asset.open("CityLine.xml");
SAXParserFactory spf = SAXParserFactory.newInstance();
SAXParser parser = spf.newSAXParser();
MyXMLHandler handler = new MyXMLHandler();
parser.parse(input, handler);
input.close();
mData = handler.getmData();// 获取解析出来的数据
}catch (Exception e) {
e.printStackTrace();
}
TextView tt=(TextView)findViewById(R.id.tt);
tt.setText(mData.get(0).toString());//打印第一个
}
}</span>
以下是打印值和效果: