Android中Xml数据存储与解析

无事心不空,有事心不乱。不管发生什么,都不要放弃,坚持走下去,肯定会有意想不到的风景。也许不是你本来想走的路,也不是你本来想登临的山,可另一条路有另一条路的风景,不同的山也一样会有美丽的日出,不要念念不忘原来的路。

XML简介:

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更简明,而且不需要扫描完整个流;

1、XML数据的备份存储:

背景描述:使用XML备份手机短信,作为源数据,后续对该XML文件进行解析;
<--!Androidmanifest代码:短信读写的权限与外部存储SD卡读写权限的添加-->
<?xml version="1.0" encoding="utf-8"?>
<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,供后续解析案例使用

  <?xml version="1.0" encoding="utf-8" standalone="yes" ?> 
- <smss>
- <sms>
  <address>119</address> 
  <date>1503645718771</date> 
  <type>2</type> 
  <body>guohuo</body> 
  </sms>
- <sms>
  <address>110</address> 
  <date>1503645687470</date> 
  <type>2</type> 
  <body>guozhe</body> 
  </sms>
- <sms>
  <address>120</address> 
  <date>1503645650256</date> 
  <type>2</type> 
  <body>huozhe</body> 
  </sms>
  </smss>

解析前的准备:
1、将上述生成的xml存储文件放到Assets目录中;
2、生成对应的Bean对象
3、开始相应的解析方法

2、XML数据的DOM解析;

 /**
     * Dom解析方法的使用
     * @param inputStream
     * @return
     * @throws Exception
     */
    public  List<SmsInfo> domResolveXml (InputStream inputStream) throws Exception {
        //初始化存储解析数据的list集合
        List<SmsInfo> 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<smssList.getLength();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<childNodes.getLength();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;
    }

3、XML数据的SAX解析;

  /**
     * SAX解析方法的使用
     *
     * @param inputStream
     * @return
     * @throws Exception
     */
    public List<SmsInfo> 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<SmsInfo> getList() {
            return smsInfosListSax;
        }
    }

4、XML数据的SAX解析;

  /**
     * XmlPull解析方法
     *
     * @param inputStream
     * @return
     * @throws Exception
     */
    public List<SmsInfo> pullResolveXml(InputStream inputStream) throws Exception {
        List<SmsInfo> 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<SmsInfo>();
//                    }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;
    }
}

5、各个解析方法的调用类代码

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<SmsInfo> 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<SmsInfo> 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<SmsInfo> 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();

    }
}

6、总结:

以下两张图片分别是Android项目中java代码的分类与最后的效果展示图:

java代码的分类
效果展示
“`

  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值