无事心不空,有事心不乱。不管发生什么,都不要放弃,坚持走下去,肯定会有意想不到的风景。也许不是你本来想走的路,也不是你本来想登临的山,可另一条路有另一条路的风景,不同的山也一样会有美丽的日出,不要念念不忘原来的路。
xml可扩展标记语言,标准通用标记语言的子集,是一种用于标记电子文件使其具有结构性的标记语言。xml作为承载数据的一个重要角色,在Android中常见的XML解析器分别为SAX解析器、DOM解析器和PULL解析器;
三种解析方式的优缺点:
SAX解析:
优点:
·SAX对内存的要求比较低,因为它让开发人员自己来决定所要处理的标签,特别是当开发人员只需要处理文档中所包含的部分数据,SAX这种扩展能力得到了更好的体现;
缺点:
·用SAX方式进行XML解析时,需要顺序执行,所以很难访问到同一文档中的不同数据,此外在基于该方式的解析编码过程也相对复杂;
使用场景:
·对于含有数据量十分巨大,而又不用对文档中所有数据进行遍历或者分析的时候,使用该方法十分有效,该方法不用将整个文档读入内存,而只需读取到程序所需要的文档标签处即可。
DOM解析
优点:
·XML树在内存中完整存储,因此可以直接修改其数据和结构;
·可以通过该解析器随时访问XML树中的任何一个节点;
·DOM解析器的API在使用上也相对比较简单;
缺点:
·如果XML文档体积比较大时,将文档读入内存是非常消耗系统资源的;
使用场景:
·DOM是用与平台和语言无关的方式表示XML文档的官方W3C标注。DOM是以层次结构组织的节点的结合,这个层次结构允许开发人员在树中寻找特定信息,分析该结构通常需要加载整个文档的构造层次结构,然后才能进行任何工作。DOM是基于对象层次结构的。
xmlPull解析:
android sdk提供了xmlpull api,xmlpull和sax类似,是基于流(Stream)操作文档,然后根据节点事件回调开发者编写的处理程序,因为是基于流的处理,因此xmlpull和sax都比较节约内存资源,不会像dom那样要把所有节点以对象树的形式展现在内存中。xmlpull比sax更简明,而且不需要扫描完整个流;
背景描述:使用XML备份手机短信,作为源数据,后续对该XML文件进行解析;
<--!Androidmanifest代码:短信读写的权限与外部存储SD卡读写权限的添加-->
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.wjf.seapp.smsbackup">
<uses-permission android:name="android.permission.WRITE_SMS"/>
<uses-permission android:name="android.permission.READ_SMS"/>
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"/>
<uses-permission android:name="android.permission.MOUNT_UNMOUNT_FILESYSTEMS"/>
<application
android:allowBackup="true"
android:icon="@mipmap/ic_launcher"
android:label="@string/app_name"
android:supportsRtl="true"
android:theme="@style/AppTheme">
<activity android:name=".MainActivity">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
intent-filter>
activity>
application>
manifest>
MainActivity类,实现对手机短信的备份(使用XML文件来存储)
package com.wjf.seapp.smsbackup;
import android.app.ProgressDialog;
import android.os.Environment;
import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;
import android.util.Log;
import android.view.View;
import android.widget.Button;
import com.wjf.seapp.smsbackup.engine.SmsBackup;
import java.io.File;
public class MainActivity extends AppCompatActivity {
private static final String TAG = "SmsBackup" ;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
//初始化短信备份逻辑
initSmsBackUp();
}
/**
* 实现短信备份功能
*/
private void initSmsBackUp() {
//1.初始化控件
Button bt_sms_backup = (Button) findViewById(R.id.bt_sms_backup);
//2.控件设定监听事件
bt_sms_backup.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
//备份过程中弹出对话框进度条,UI界面显示短信备份过程
showSmsBackupDialog();
}
});
}
/**
* 短信备份DialogProgress显示
*/
private void showSmsBackupDialog() {
final ProgressDialog progressDialog = new ProgressDialog(this);
progressDialog.setIcon(R.mipmap.ic_launcher);//设定dialog显示图片
progressDialog.setTitle("短信备份"); //设置dialog显示的标题
progressDialog.setProgressStyle(ProgressDialog.STYLE_HORIZONTAL);//设置dialog显示为水平样式展示
progressDialog.show();//将该布局展示出来;
//执行短信备份的逻辑,因短信数据备份有可能为耗时操作需在子线程中去执行
new Thread(){
@Override
public void run() {
//设定数据备份的具体路径和名称
String path = Environment.getExternalStorageDirectory().getAbsolutePath()+ File.separator+"smssea.xml";
Log.i(TAG,path);//外部存储的路径为:/storage/emulated/0/smssea.xml
/*为实现备份数据与progerssDialog显示界面同步,需将progerssDialog作为参数传递给backup方法,后改为回调实现,传递CallBack接口的实现类*/
SmsBackup.backup(getApplicationContext(), path, new SmsBackup.CallBack() {
@Override
public void setMax(int max) {
progressDialog.setMax(max);
}
@Override
public void setProgress(int index) {
progressDialog.setProgress(index);
}
});
//备份完成后将dialog显示界面隐藏
progressDialog.dismiss();
}
}.start();
}
}
☆☆engine短信备份工具(驱动类)的代码,其中涉及到回调方法的使用(简略介绍),代码如下☆☆
package com.wjf.seapp.smsbackup.engine;
import android.app.ProgressDialog;
import android.content.Context;
import android.database.Cursor;
import android.net.Uri;
import android.util.Xml;
import org.xmlpull.v1.XmlSerializer;
import java.io.File;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
/**
* Created by Seapp on 2017/8/25.
* 驱动类:实现对手机短信的备份的方法
*/
public class SmsBackup {
private static FileOutputStream fileOutputStream;
private static int index = 0; //记录当前进度条进度的参数;
/**
* 数据短信的备份
* @param context 上下文环境
* @param path 文件存储路径
* @param progressDialog / callBack
* progressDialog:为测试对进度框的动态设定将progressDialog作为backup的参数传递过来
* callBack:回调实现对progressDialog的设定
*/
public static void backup(Context context, String path, CallBack callBack){
//1.获取短信备份的写入文件
File file = new File(path);
//2.ContentReceiver查询手机本地的短息业务
Cursor cursor = context.getContentResolver().query(Uri.parse("content://sms/"), new String[]{"address", "date", "type", "body"}, null, null, null);
//3.获取文件对应的输出流
try {
fileOutputStream = new FileOutputStream(file);
//☆4.序列化数据库中存放的数据,存放到xml中
XmlSerializer xmlSerializer = Xml.newSerializer();
//☆5.给xml做相应的设置
xmlSerializer.setOutput(fileOutputStream,"utf-8");
xmlSerializer.startDocument("utf-8",true);
xmlSerializer.startTag(null,"smss");
if(cursor != null){
//设置进度条显示的最大值
// progressDialog.setMax(cursor.getCount());
callBack.setMax(cursor.getCount());
}
if(cursor!= null & cursor.moveToFirst()){
do{
xmlSerializer.startTag(null,"sms");
//电话号码存储
xmlSerializer.startTag(null,"address");
xmlSerializer.text(cursor.getString(0));
xmlSerializer.endTag(null,"address");
//短信发送时间存储
xmlSerializer.startTag(null,"date");
xmlSerializer.text(cursor.getString(1));
xmlSerializer.endTag(null,"date");
//短信发送类型存储
xmlSerializer.startTag(null,"type");
xmlSerializer.text(cursor.getString(2));
xmlSerializer.endTag(null,"type");
//短信内容存储
xmlSerializer.startTag(null,"body");
xmlSerializer.text(cursor.getString(3));
xmlSerializer.endTag(null,"body");
xmlSerializer.endTag(null,"sms");
//短信备份一次,对应的进度条数量加一
index ++;
Thread.sleep(500);
//给dialog设定当前进度
// progressDialog.setProgress(index);
callBack.setProgress(index);
}while (cursor.moveToNext());
}
xmlSerializer.endTag(null,"smss");
xmlSerializer.endDocument();
} catch (Exception e) {
e.printStackTrace();
}finally {
//关闭cursor以及写入流;
if(cursor != null && fileOutputStream != null){
try {
cursor.close();
fileOutputStream.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
//使用回调实现ProgerssDialog的设定
//1.定义一个接口
public interface CallBack{
//2.接口中定义未实现的业务逻辑方法;
//3.传递一个实现了此类接口的实现类对象到本工具类中
//4.获取传递进来的对象,在合适的地方做方法调用;
/**
* 进度条总数的设定,可由调用类确定使用哪种进度条来显示备份UI;
* @param max
*/
public void setMax(int max);
/**
* 进度条当前进度的设定,可由调用类确定使用哪种进度条来显示备份UI;
* @param index
*/
public void setProgress(int index);
}
}
短信备份文件seasms.xml,供后续解析案例使用
- <smss>
- <sms>
<address>119address>
<date>1503645718771date>
<type>2type>
<body>guohuobody>
sms>
- <sms>
<address>110address>
<date>1503645687470date>
<type>2type>
<body>guozhebody>
sms>
- <sms>
<address>120address>
<date>1503645650256date>
<type>2type>
<body>huozhebody>
sms>
smss>
解析前的准备:
1、将上述生成的xml存储文件放到Assets目录中;
2、生成对应的Bean对象
3、开始相应的解析方法
/**
* Dom解析方法的使用
* @param inputStream
* @return
* @throws Exception
*/
public List domResolveXml (InputStream inputStream) throws Exception {
//初始化存储解析数据的list集合
List smsInfolistDom = new ArrayList<>();
//初始化DOM
DocumentBuilderFactory documentBuilderFactory = DocumentBuilderFactory.newInstance();
DocumentBuilder builder = documentBuilderFactory.newDocumentBuilder();
//获取DOM对象
Document document = builder.parse(inputStream);
//获取短信信息的List
NodeList smssList = document.getElementsByTagName("sms");
//遍历smssList标签
for(int i = 0;i//获取Smss标签
Node node_smss = smssList.item(i);
//获取Smss标签里面的sms标签
NodeList childNodes = node_smss.getChildNodes();
//新建SmsInfo对象
SmsInfo smsInfo = new SmsInfo();
//遍历smsInfo标签中的标签
for(int j = 0; j//获取定义的“address/date/body/type”等标签信息
Node node = childNodes.item(j);
switch(node.getNodeName()){
case "address":
String address = node.getTextContent();
smsInfo.setAddress(address);
break;
case "date":
String date = node.getTextContent();
smsInfo.setDate(date);
break;
case "type":
String type = node.getTextContent();
smsInfo.setType(type);
break;
case "body":
String body = node.getTextContent();
smsInfo.setBody(body);
}
}
smsInfolistDom.add(smsInfo);
}
return smsInfolistDom;
}
/**
* SAX解析方法的使用
*
* @param inputStream
* @return
* @throws Exception
*/
public List saxResolveXml(InputStream inputStream) throws Exception {
//1.初始化SAX解析器
SAXParserFactory saxParserFactory = SAXParserFactory.newInstance();
SAXParser saxParser = saxParserFactory.newSAXParser();
//2.新建解析处理器
MyHealder myHealder = new MyHealder();
//3.将解析交于处理器
saxParser.parse(inputStream, myHealder);
//4.获取解析后的结果
return myHealder.getList();
}
/**
* SAX解析的处理器
*/
public class MyHealder extends DefaultHandler {
private List smsInfosListSax;
private SmsInfo smsInfo;
private String tempString;
public MyHealder() {
super();
}
/**
* 解析到文档开始时调用,一般做初始化操作
*
* @throws SAXException
*/
@Override
public void startDocument() throws SAXException {
//初始化存储xml集合的list列表
smsInfosListSax = new ArrayList<>();
super.startDocument();
}
/**
* 解析到文档结尾时调用,一般做回收操作
*
* @throws SAXException
*/
@Override
public void endDocument() throws SAXException {
super.endDocument();
}
/**
* 每读取一个元素就调用该方法,
*
* @param uri
* @param localName
* @param qName
* @param attributes
* @throws SAXException
*/
@Override
public void startElement(String uri, String localName, String qName, Attributes attributes) throws SAXException {
if ("sms".equals(qName)) {
//读到Smss标签
smsInfo = new SmsInfo();
}
super.startElement(uri, localName, qName, attributes);
}
/**
* 读取到元素结尾时调用该方法
*
* @param uri
* @param localName
* @param qName
* @throws SAXException
*/
@Override
public void endElement(String uri, String localName, String qName) throws SAXException {
switch (qName) {
case "sms":
smsInfosListSax.add(smsInfo);
break;
case "address":
smsInfo.setAddress(tempString);
break;
case "date":
smsInfo.setDate(tempString);
break;
case "type":
smsInfo.setType(tempString);
break;
case "body":
smsInfo.setBody(tempString);
}
super.endElement(uri, localName, qName);
}
/**
* 获取属性内容是调用该方法
*
* @param ch
* @param start
* @param length
* @throws SAXException
*/
@Override
public void characters(char[] ch, int start, int length) throws SAXException {
tempString = new String(ch, start, length);
super.characters(ch, start, length);
}
public List getList() {
return smsInfosListSax;
}
}
/**
* XmlPull解析方法
*
* @param inputStream
* @return
* @throws Exception
*/
public List pullResolveXml(InputStream inputStream) throws Exception {
List smsInfosListPull = null;
SmsInfo smsInfo = null;
//1.创建pullXml解析器
XmlPullParser xmlPullParser = Xml.newPullParser();
//2.初始化pullXml解析器
xmlPullParser.setInput(inputStream, "utf-8");
//3.获取读取文件的类型
int xmlType = xmlPullParser.getEventType();
//4.通过判断文件读取类型来进行读取
while (xmlType != XmlPullParser.END_DOCUMENT) {
switch (xmlType) {
//开始标签
case XmlPullParser.START_TAG:
//区分不同的开始标签
// if("smss".equals(xmlPullParser.getName())){
// smsInfosListPull = new ArrayList();
// }else if("sms".equals(xmlPullParser.getName())){
// smsInfo = new SmsInfo();
// }else if("address".equals(xmlPullParser.getName())){
// smsInfo.setAddress(xmlPullParser.nextText());
// }else if ("date".equals(xmlPullParser.nextText())){
// smsInfo.setDate(xmlPullParser.nextText());
// }else if ("type".equals(xmlPullParser.getName())){
// smsInfo.setType(xmlPullParser.nextText());
// }else if ("body".equals(xmlPullParser.getName())){
// smsInfo.setBody(xmlPullParser.nextText());
// }
switch (xmlPullParser.getName()) {
case "smss":
Log.i(tag, "列表集合已创建");
smsInfosListPull = new ArrayList<>();
break;
case "sms":
smsInfo = new SmsInfo();
Log.i(tag, "SmsInfo对象已创建");
break;
case "address":
String address = xmlPullParser.nextText();
Log.i(tag, address);
smsInfo.setAddress(address);
break;
case "date":
String date = xmlPullParser.nextText();
smsInfo.setDate(date);
break;
case "type":
String type = xmlPullParser.nextText();
smsInfo.setType(type);
break;
case "body":
String body = xmlPullParser.nextText();
smsInfo.setBody(body);
}
//结束标签
case XmlPullParser.END_TAG:
if ("sms".equals(xmlPullParser.getName())) {
smsInfosListPull.add(smsInfo);
}
break;
}
//继续读取下一个标签
xmlType = xmlPullParser.next();
}
//返回解析后的数据结果
return smsInfosListPull;
}
}
package com.wjf.seapp.smsbackup;
import android.app.ProgressDialog;
import android.os.Environment;
import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;
import android.util.Log;
import android.view.View;
import android.widget.Button;
import android.widget.TextView;
import com.wjf.seapp.smsbackup.bean.SmsInfo;
import com.wjf.seapp.smsbackup.engine.SmsBackup;
import com.wjf.seapp.smsbackup.utils.XmlUtils;
import java.io.File;
import java.util.List;
public class MainActivity extends AppCompatActivity {
private static final String TAG = "SmsBackup" ;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
//初始化短信备份逻辑
initSmsBackUp();
//解析xml文件(smssea.xml)
resolveXml();
}
/**
* 解析XML文件的三种办法
*/
private void resolveXml() {
//初始化控件
final TextView tv_result = (TextView) findViewById(R.id.tv_result);
Button bt_dom = (Button) findViewById(R.id.bt_dom);
Button bt_sax = (Button) findViewById(R.id.bt_sax);
Button bt_pull = (Button) findViewById(R.id.bt_pull);
//dom解析方法的调用
bt_dom.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
XmlUtils xmlUtils = new XmlUtils();
try {
List smsInfos = xmlUtils.domResolveXml(getResources().getAssets().open("smssea.xml"));
tv_result.setText(smsInfos.toString());
} catch (Exception e) {
e.printStackTrace();
}
}
});
//sax解析方法的调用
bt_sax.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
XmlUtils xmlUtils = new XmlUtils();
try {
List smsInfos = xmlUtils.saxResolveXml(getResources().getAssets().open("smssea.xml"));
tv_result.setText(smsInfos.toString());
} catch (Exception e) {
e.printStackTrace();
}
}
});
//pull解析方法的调用
bt_pull.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
XmlUtils xmlUtils = new XmlUtils();
try {
List smsInfos = xmlUtils.pullResolveXml(getResources().getAssets().open("smssea.xml"));
tv_result.setText(smsInfos.toString());
} catch (Exception e) {
e.printStackTrace();
}
}
});
}
/**
* 实现短信备份功能
*/
private void initSmsBackUp() {
//1.初始化控件
Button bt_sms_backup = (Button) findViewById(R.id.bt_sms_backup);
//2.控件设定监听事件
bt_sms_backup.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
//备份过程中弹出对话框进度条,UI显示短信备份过程
showSmsBackupDialog();
}
});
}
/**
* 短信备份DialogProgress显示
*/
private void showSmsBackupDialog() {
final ProgressDialog progressDialog = new ProgressDialog(this);
progressDialog.setIcon(R.mipmap.ic_launcher);//设定dialog显示图片
progressDialog.setTitle("短信备份"); //设置dialog显示的标题
progressDialog.setProgressStyle(ProgressDialog.STYLE_HORIZONTAL);//设置dialog显示为水平样式展示
progressDialog.show();//将该布局展示出来;
//执行短信备份的逻辑,因短信数据备份有可能为耗时操作需在子线程中去执行
new Thread(){
@Override
public void run() {
//设定数据备份的具体路径和名称
String path = Environment.getExternalStorageDirectory().getAbsolutePath()+ File.separator+"smssea.xml";
Log.i(TAG,path);//外部存储的路径为:/storage/emulated/0/smssea.xml
/*为实现备份数据与progerssDialog显示界面同步,需将progerssDialog作为参数传递给backup方法*/
SmsBackup.backup(getApplicationContext(), path, new SmsBackup.CallBack() {
@Override
public void setMax(int max) {
progressDialog.setMax(max);
}
@Override
public void setProgress(int index) {
progressDialog.setProgress(index);
}
});
//备份完成后将dialog显示界面隐藏
progressDialog.dismiss();
}
}.start();
}
}
以下两张图片分别是Android项目中java代码的分类与最后的效果展示图: