仿京东商城系列18------xml文件读取(地址选择器)

本项目来自菜鸟窝,有兴趣者点击http://www.cniao5.com/course/

项目已经做完,
https://github.com/15829238397/CN5E-shop


仿京东商城系列0------项目简介
仿京东商城系列1------fragmentTabHost实现底部导航栏
仿京东商城系列2------自定义toolbar
仿京东商城系列3------封装Okhttp
仿京东商城系列4------轮播广告条
仿京东商城系列5------商品推荐栏
仿京东商城系列6------下拉刷新上拉加载的商品列表
仿京东商城系列7------商品分类页面
仿京东商城系列8------自定义的数量控制器
仿京东商城系列9------购物车数据存储器实现
仿京东商城系列10------添加购物车,管理购物车功能实现
仿京东商城系列11------商品排序功能以及布局切换实现(Tablayout)
仿京东商城系列12------商品详细信息展示(nativie与html交互)
仿京东商城系列13------商品分享(shareSDK)
仿京东商城系列14------用户登录以及app登录拦截
仿京东长城系列15------用户注册,SMSSDK集成
仿京东商城系列16------支付SDK集成
仿京东商城系列17------支付功能实现
仿京东商城系列18------xml文件读取(地址选择器)
仿京东商城系列19------九宫格订单展示
仿京东商城系列20------终章


前言

我们接着上一更的内容,上一更我们集成并使用了支付SDK完成了模拟支付。但我们的订单编辑页面地址与收货人信息一栏还是空白,今天我们要做的就是填充这个空白。效果图如下:

地址选择器.gif

内容

补充新知识

xml文件读取

解析方式

1、DOM解析器
DOM(Document Object Model) 是一种用于XML文档的对象模型,可用于直接访问XML文档的各个部分。它是一次性全部将内容加载在内存中,生成一个树状结构,它没有涉及回调和复杂的状态管理。 缺点是加载大文档时效率低下,所以一般在解析大文档时不建议使用DOM解析。
分析该结构通常需要加载整个文档和构造树形结构,然后才可以检索和更新节点信息。Android完全支持DOM 解析。利用DOM中的对象,可以对XML文档进行读取、搜索、修改、添加和删除等操作。
DOM的工作原理:使用DOM对XML文件进行操作时,首先要解析文件,将文件分为独立的元素、属性和注释等,然后以节点树的形式在内存中对XML文件进行表示,就可以通过节点树访问文档的内容,并根据需要修改文档。
常用的DOM的接口和类:
Document:该接口定义分析并创建DOM文档的一系列方法,它是文档树的根,是操作DOM的基础。
Node:该接口提供处理并获取节点和子节点值的方法。
Element:该接口继承Node接口,提供了获取、修改XML元素名字和属性的方法。
NodeList:提供获得节点个数和当前节点的方法。这样就可以迭代地访问各个节点。
DOMParser:该类是Apache的Xerces中的DOM解析器类,可直接解析XML文件。

2、SAX解析
SAX(Simple API for XML) 使用流式处理的方式,它并不记录所读内容的相关信息。它是一种以事件为驱动的XML API,解析速度快,占用内存少。使用回调函数来实现。 缺点是因为以事件为驱动的它不能回退。
它的核心是事件处理模式,主要是围绕着事件源以及事件处理器来工作的。当事件源产生事件后,调用事件处理器相应的处理方法,一个事件就可以得到处理。在事件源调用事件处理器中特定方法的时候,还要传递给事件处理器相应事件的状态信息,这样事件处理器才能够根据提供的事件信息来决定自己的行为。
SAX的工作原理:SAX会顺序扫描文档,在扫描到文档(document)开始与结束、元素(element)开始与结束、元素内容(characters)等时通知事件处理方法,事件处理方法进行相应处理,然后继续扫描,指导文档扫描结束。
常用的SAX接口和类:
Attrbutes:用于得到属性的个数、名字和值。
ContentHandler:定义与文档本身关联的事件(例如,开始和结束标记)。大多数应用程序都注册这些事件。
DTDHandler:定义与DTD关联的事件。它没有定义足够的事件来完整地报告DTD。如果需要对DTD进行语法分析,请使用可选的DeclHandler。
DeclHandler是SAX的扩展。不是所有的语法分析器都支持它。
EntityResolver:定义与装入实体关联的事件。只有少数几个应用程序注册这些事件。
ErrorHandler:定义错误事件。许多应用程序注册这些事件以便用它们自己的方式报错。
DefaultHandler:它提供了这些接LI的缺省实现。在大多数情况下,为应用程序扩展DefaultHandler并覆盖相关的方法要比直接实现一个接口更容易。
下面是部分说明:

SAX处理器说明

部分常用方法说明

    所以,我们通常要使用XmlReader和DefaultHandler配合起来解析xml文档。
    SAX的解析流程:

startDocument --> startElement --> characters --> endElement --> endDocument

3、pull解析
Pull内置于Android系统中。也是官方解析布局文件所使用的方式。Pull与SAX有点类似,都提供了类似的事件,如开始元素和结束元素。不同的是,SAX的事件驱动是回调相应方法,需要提供回调的方法,而后在SAX内部自动调用相应的方法。而Pull解析器并没有强制要求提供触发的方法。因为他触发的事件不是一个方法,而是一个数字。它使用方便,效率高。Android官方推荐开发者们使用Pull解析技术。Pull解析技术是第三方开发的开源技术,它同样可以应用于JavaSE开发。
pull返回的常量:
读取到xml的声明返回 START_DOCUMENT;
读取到xml的结束返回 END_DOCUMENT ;
读取到xml的开始标签返回 START_TAG;
读取到xml的结束标签返回 END_TAG;
读取到xml的文本返回 TEXT;
pull的工作原理:pull提供了开始元素和结束元素。当某个元素开始时,我们可以调用parser.nextText从XML文档中提取所有字符数据。当解释到一个文档结束时,自动生成EndDocument事件。
常用的XML pull的接口和类:
XmlPullParser:XML pull解析器是一个在XMLPULL VlAP1中提供了定义解析功能的接口。
XmlSerializer:它是一个接口,定义了XML信息集的序列。
XmlPullParserFactory:这个类用于在XMPULL V1 API中创建XML Pull解析器。
XmlPullParserException:抛出单一的XML pull解析器相关的错误。
pull的解析流程:
start_document --> end_document --> start_tag -->end_tag

**在Android中还有第四种方式:android.util.Xml类 **(本人未使用过)
在Android API中,另外提供了Android.util.Xml类,同样可以解析XML文件,使用方法类似SAX,也都需编写Handler来处理XML的解析,但是在使用上却比SAX来得简单 ,如下所示:
以android.util.XML实现XML解析 :
MyHandler myHandler=new MyHandler0;
android.util.Xm1.parse(url.openC0nnection().getlnputStream(),Xml.Encoding.UTF-8,myHandler);

代码讲解

了解完概念,我们就可以着手解析xml文件了。接下来我来讲述以下解析xml文件的步骤。

  • 将xml文件放在main->assets目录下。
  • 新建一个类XmlParserHandler继承DefaultHandler,并实现相关方法。代码如下:
    xml文件:

  
    
      
      
      
      
      
      
      
      
      
      
      
      
    
    ......

XmlParserHandler类代码:

package com.example.cne_shop.bean.city;

import android.util.Log;

import com.example.cne_shop.bean.city.model.CityModel;
import com.example.cne_shop.bean.city.model.DistrictModel;
import com.example.cne_shop.bean.city.model.PrivinceModel;

import org.xml.sax.Attributes;
import org.xml.sax.SAXException;
import org.xml.sax.helpers.DefaultHandler;

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

import static android.content.ContentValues.TAG;

/**
 * Created by 博 on 2017/7/27.
 */

public class XmlParserHandler extends DefaultHandler {

    private List privinceModels ;
    private List cityModels ;
    private List districtModels ;
    private PrivinceModel privinceModel ;
    private DistrictModel districtModel ;
    private CityModel cityModel ;
    private String preTag ;

    public List getPrivinceModels() {
        return privinceModels;
    }

    @Override
    public void startDocument() throws SAXException {
        super.startDocument();
        privinceModels = new ArrayList<>() ;

        Log.d(TAG, "startDocument: ------------------------------");

        //当读到第一个标签的时候会触发这个方法
    }

    @Override
    public void startElement(String uri, String localName, String qName, Attributes attributes) throws SAXException {
        super.startElement(uri, localName, qName, attributes);
        //开始解析节点

        if ("province".equals(localName)){

            Log.d(TAG, "新建省: --------------------------------------------");
            cityModels = new ArrayList<>() ;
            privinceModel = new PrivinceModel() ;
            privinceModel.setName(attributes.getValue("name") );

        }else if ("city".equals(localName)){

            districtModels = new ArrayList<>() ;
            cityModel = new CityModel() ;
            cityModel.setName(attributes.getValue("name") );
        }else if ("district".equals(localName)){

            districtModel = new DistrictModel() ;
            districtModel.setName(attributes.getValue("name") );
            districtModel.setZipcode(attributes.getValue("zipcode") );
        }

        preTag = localName ;

    }

    public void endDocument () {
        //文档解析结束
        Log.d(TAG, "endDocument: --------------------------------------------");

    }

    public void characters (char[] ch, int start, int length) {
        //保存节点内容

   if ("province".equals(preTag)){
            privinceModels.add(privinceModel) ;
            Log.d(TAG, "添加省: --------------------------------------------");

        }else if ("city".equals(preTag)){
            cityModels.add(cityModel) ;
            privinceModel.setCityModels(cityModels);
       Log.d(TAG, "添加市: --------------------------------------------");
        }else if ("district".equals(preTag)){
            districtModels.add(districtModel) ;
            cityModel.setDistrictModels(districtModels);
       Log.d(TAG, "添加县: --------------------------------------------");
        }

        preTag = null ;

    }

    public void endElement (String uri, String localName, String qName) {
        //结束解析节点

        Log.d(TAG, "endElement: ------------------------"+ uri + "   " + localName + " " + qName);
    }
}
  • 调用新建类XmlParserHandler代码如下:
 SAXParserFactory spf = SAXParserFactory.newInstance();
        SAXParser sp = spf.newSAXParser();
        XmlParserHandler sfh = new XmlParserHandler();

        AssetManager am = this.getAssets();
        InputStream is = am.open("province_data.xml");

        sp.parse(is , sfh);
        getAdrMsg(sfh.getPrivinceModels()) ;

地址选择器实现

pickerView简介

这是一款仿iOS的PickerView控件,有时间选择和选项选择,并支持一二三级联动,支持自定义样式,3.x新版本的详细特性如下:

有时间和选项这两种选择器
选项选择器支持三级联动
时间选择器支持起始和终止日期设定
支持“年,月,日,时,分,秒”,“省,市,区”等选项的单位(label)显示、隐藏和自定义。
支持自定义文字、颜色、文字大小等属性
支持背景颜色更换,有夜间模式需求的问题可以解决了
Item的文字长度过长时,文字会自适应缩放到Item的长度,避免显示不完全的问题
——TimePickerView 时间选择器,支持年月日时分,年月日,年月,时分等格式
——OptionsPickerView 选项选择器,支持一,二,三级选项选择,并且可以设置是否联动

TimePicker.gif
TimePickerNight.gif

Province.gif
CustomLayout.gif

  • 详细了解请戳github
pickerView代码调用

下面是地址选择器的代码调用

   OptionsPickerView  pvOptions = new  OptionsPickerView.Builder(this, new OptionsPickerView.OnOptionsSelectListener() {
            @Override
            public void onOptionsSelect(int options1, int option2, int options3 ,View v) {
                //返回的分别是三个级别的选中位置
                consigneeAdr.setText(province.get(options1) + city.get(options1).get(option2) + county.get(options1).get(option2).get(options3));
                zip_code = zip_codes.get(options1).get(option2).get(options3) ;
            }
        })
                .setSubmitText("确定")//确定按钮文字
                .setCancelText("取消")//取消按钮文字
                .setTitleText("城市选择")//标题
                .setSubCalSize(18)//确定和取消文字大小
                .setTitleSize(20)//标题文字大小
                .setTitleColor(Color.BLACK)//标题文字颜色
                .setSubmitColor(Color.BLACK)//确定按钮文字颜色
                .setCancelColor(Color.BLACK)//取消按钮文字颜色
                .setTitleBgColor(Color.WHITE)//标题背景颜色 Night mode
                .setBgColor(Color.WHITE)//滚轮背景颜色 Night mode
                .setContentTextSize(18)//滚轮文字大小
//                .setLinkage(false)//设置是否联动,默认true
                .setLabels("", "", "")//设置选择的三级单位
                .isCenterLabel(false) //是否只显示中间选中项的label文字,false则每项item全部都带有label。
                .setCyclic(false, false, false)//循环与否
                .setSelectOptions(1, 1, 1)  //设置默认选中项
                .setOutSideCancelable(false)//点击外部dismiss default true
                .isDialog(true)//是否显示为对话框样式
                .build();

//        Log.d("----" , "--------------"+county.get(1).get(1).get(1)) ;

        pvOptions.setPicker(province, city  , county);//添加数据源
        pvOptions.show();

没有什么要讲了的,都在注释里,这样我们就可以调用好玩的地址选择器啦。


其他部分没有什么要说的,就是简单布局,网络申请,处理信息,布拉布拉。完整代码请戳页首github地址。

你可能感兴趣的:(仿京东商城系列18------xml文件读取(地址选择器))