本項(xiàng)目來(lái)自菜鳥(niǎo)窩,有興趣者點(diǎn)擊http://www.cniao5.com/course/
項(xiàng)目已經(jīng)做完,
https://github.com/15829238397/CN5E-shop
仿京東商城系列0------項(xiàng)目簡(jiǎn)介
仿京東商城系列1------fragmentTabHost實(shí)現(xiàn)底部導(dǎo)航欄
仿京東商城系列2------自定義toolbar
仿京東商城系列3------封裝Okhttp
仿京東商城系列4------輪播廣告條
仿京東商城系列5------商品推薦欄
仿京東商城系列6------下拉刷新上拉加載的商品列表
仿京東商城系列7------商品分類(lèi)頁(yè)面
仿京東商城系列8------自定義的數(shù)量控制器
仿京東商城系列9------購(gòu)物車(chē)數(shù)據(jù)存儲(chǔ)器實(shí)現(xiàn)
仿京東商城系列10------添加購(gòu)物車(chē),管理購(gòu)物車(chē)功能實(shí)現(xiàn)
仿京東商城系列11------商品排序功能以及布局切換實(shí)現(xiàn)(Tablayout)
仿京東商城系列12------商品詳細(xì)信息展示(nativie與html交互)
仿京東商城系列13------商品分享(shareSDK)
仿京東商城系列14------用戶(hù)登錄以及app登錄攔截
仿京東長(zhǎng)城系列15------用戶(hù)注冊(cè),SMSSDK集成
仿京東商城系列16------支付SDK集成
仿京東商城系列17------支付功能實(shí)現(xiàn)
仿京東商城系列18------xml文件讀取(地址選擇器)
仿京東商城系列19------九宮格訂單展示
仿京東商城系列20------終章
前言
我們接著上一更的內(nèi)容,上一更我們集成并使用了支付SDK完成了模擬支付。但我們的訂單編輯頁(yè)面地址與收貨人信息一欄還是空白,今天我們要做的就是填充這個(gè)空白。效果圖如下:
內(nèi)容
補(bǔ)充新知識(shí)
xml文件讀取
解析方式
1、DOM解析器
DOM(Document Object Model) 是一種用于XML文檔的對(duì)象模型,可用于直接訪問(wèn)XML文檔的各個(gè)部分。它是一次性全部將內(nèi)容加載在內(nèi)存中,生成一個(gè)樹(shù)狀結(jié)構(gòu),它沒(méi)有涉及回調(diào)和復(fù)雜的狀態(tài)管理。 缺點(diǎn)是加載大文檔時(shí)效率低下,所以一般在解析大文檔時(shí)不建議使用DOM解析。
分析該結(jié)構(gòu)通常需要加載整個(gè)文檔和構(gòu)造樹(shù)形結(jié)構(gòu),然后才可以檢索和更新節(jié)點(diǎn)信息。Android完全支持DOM 解析。利用DOM中的對(duì)象,可以對(duì)XML文檔進(jìn)行讀取、搜索、修改、添加和刪除等操作。
DOM的工作原理:使用DOM對(duì)XML文件進(jìn)行操作時(shí),首先要解析文件,將文件分為獨(dú)立的元素、屬性和注釋等,然后以節(jié)點(diǎn)樹(shù)的形式在內(nèi)存中對(duì)XML文件進(jìn)行表示,就可以通過(guò)節(jié)點(diǎn)樹(shù)訪問(wèn)文檔的內(nèi)容,并根據(jù)需要修改文檔。
常用的DOM的接口和類(lèi):
Document:該接口定義分析并創(chuàng)建DOM文檔的一系列方法,它是文檔樹(shù)的根,是操作DOM的基礎(chǔ)。
Node:該接口提供處理并獲取節(jié)點(diǎn)和子節(jié)點(diǎn)值的方法。
Element:該接口繼承Node接口,提供了獲取、修改XML元素名字和屬性的方法。
NodeList:提供獲得節(jié)點(diǎn)個(gè)數(shù)和當(dāng)前節(jié)點(diǎn)的方法。這樣就可以迭代地訪問(wèn)各個(gè)節(jié)點(diǎn)。
DOMParser:該類(lèi)是Apache的Xerces中的DOM解析器類(lèi),可直接解析XML文件。
2、SAX解析
SAX(Simple API for XML) 使用流式處理的方式,它并不記錄所讀內(nèi)容的相關(guān)信息。它是一種以事件為驅(qū)動(dòng)的XML API,解析速度快,占用內(nèi)存少。使用回調(diào)函數(shù)來(lái)實(shí)現(xiàn)。 缺點(diǎn)是因?yàn)橐允录轵?qū)動(dòng)的它不能回退。
它的核心是事件處理模式,主要是圍繞著事件源以及事件處理器來(lái)工作的。當(dāng)事件源產(chǎn)生事件后,調(diào)用事件處理器相應(yīng)的處理方法,一個(gè)事件就可以得到處理。在事件源調(diào)用事件處理器中特定方法的時(shí)候,還要傳遞給事件處理器相應(yīng)事件的狀態(tài)信息,這樣事件處理器才能夠根據(jù)提供的事件信息來(lái)決定自己的行為。
SAX的工作原理:SAX會(huì)順序掃描文檔,在掃描到文檔(document)開(kāi)始與結(jié)束、元素(element)開(kāi)始與結(jié)束、元素內(nèi)容(characters)等時(shí)通知事件處理方法,事件處理方法進(jìn)行相應(yīng)處理,然后繼續(xù)掃描,指導(dǎo)文檔掃描結(jié)束。
常用的SAX接口和類(lèi):
Attrbutes:用于得到屬性的個(gè)數(shù)、名字和值。
ContentHandler:定義與文檔本身關(guān)聯(lián)的事件(例如,開(kāi)始和結(jié)束標(biāo)記)。大多數(shù)應(yīng)用程序都注冊(cè)這些事件。
DTDHandler:定義與DTD關(guān)聯(lián)的事件。它沒(méi)有定義足夠的事件來(lái)完整地報(bào)告DTD。如果需要對(duì)DTD進(jìn)行語(yǔ)法分析,請(qǐng)使用可選的DeclHandler。
DeclHandler是SAX的擴(kuò)展。不是所有的語(yǔ)法分析器都支持它。
EntityResolver:定義與裝入實(shí)體關(guān)聯(lián)的事件。只有少數(shù)幾個(gè)應(yīng)用程序注冊(cè)這些事件。
ErrorHandler:定義錯(cuò)誤事件。許多應(yīng)用程序注冊(cè)這些事件以便用它們自己的方式報(bào)錯(cuò)。
DefaultHandler:它提供了這些接LI的缺省實(shí)現(xiàn)。在大多數(shù)情況下,為應(yīng)用程序擴(kuò)展DefaultHandler并覆蓋相關(guān)的方法要比直接實(shí)現(xiàn)一個(gè)接口更容易。
下面是部分說(shuō)明:
部分常用方法說(shuō)明
所以,我們通常要使用XmlReader和DefaultHandler配合起來(lái)解析xml文檔。
SAX的解析流程:
startDocument --> startElement --> characters --> endElement --> endDocument
3、pull解析
Pull內(nèi)置于Android系統(tǒng)中。也是官方解析布局文件所使用的方式。Pull與SAX有點(diǎn)類(lèi)似,都提供了類(lèi)似的事件,如開(kāi)始元素和結(jié)束元素。不同的是,SAX的事件驅(qū)動(dòng)是回調(diào)相應(yīng)方法,需要提供回調(diào)的方法,而后在SAX內(nèi)部自動(dòng)調(diào)用相應(yīng)的方法。而Pull解析器并沒(méi)有強(qiáng)制要求提供觸發(fā)的方法。因?yàn)樗|發(fā)的事件不是一個(gè)方法,而是一個(gè)數(shù)字。它使用方便,效率高。Android官方推薦開(kāi)發(fā)者們使用Pull解析技術(shù)。Pull解析技術(shù)是第三方開(kāi)發(fā)的開(kāi)源技術(shù),它同樣可以應(yīng)用于JavaSE開(kāi)發(fā)。
pull返回的常量:
讀取到xml的聲明返回 START_DOCUMENT;
讀取到xml的結(jié)束返回 END_DOCUMENT ;
讀取到xml的開(kāi)始標(biāo)簽返回 START_TAG;
讀取到xml的結(jié)束標(biāo)簽返回 END_TAG;
讀取到xml的文本返回 TEXT;
pull的工作原理:pull提供了開(kāi)始元素和結(jié)束元素。當(dāng)某個(gè)元素開(kāi)始時(shí),我們可以調(diào)用parser.nextText從XML文檔中提取所有字符數(shù)據(jù)。當(dāng)解釋到一個(gè)文檔結(jié)束時(shí),自動(dòng)生成EndDocument事件。
常用的XML pull的接口和類(lèi):
XmlPullParser:XML pull解析器是一個(gè)在XMLPULL VlAP1中提供了定義解析功能的接口。
XmlSerializer:它是一個(gè)接口,定義了XML信息集的序列。
XmlPullParserFactory:這個(gè)類(lèi)用于在XMPULL V1 API中創(chuàng)建XML Pull解析器。
XmlPullParserException:拋出單一的XML pull解析器相關(guān)的錯(cuò)誤。
pull的解析流程:
start_document --> end_document --> start_tag -->end_tag
**在Android中還有第四種方式:android.util.Xml類(lèi) **(本人未使用過(guò))
在Android API中,另外提供了Android.util.Xml類(lèi),同樣可以解析XML文件,使用方法類(lèi)似SAX,也都需編寫(xiě)Handler來(lái)處理XML的解析,但是在使用上卻比SAX來(lái)得簡(jiǎn)單 ,如下所示:
以android.util.XML實(shí)現(xiàn)XML解析 :
MyHandler myHandler=new MyHandler0;
android.util.Xm1.parse(url.openC0nnection().getlnputStream(),Xml.Encoding.UTF-8,myHandler);
代碼講解
了解完概念,我們就可以著手解析xml文件了。接下來(lái)我來(lái)講述以下解析xml文件的步驟。
- 將xml文件放在main->assets目錄下。
- 新建一個(gè)類(lèi)XmlParserHandler繼承DefaultHandler,并實(shí)現(xiàn)相關(guān)方法。代碼如下:
xml文件:
<root>
<province name="安徽省">
<city name="安慶市">
<district name="樅陽(yáng)縣" zipcode="246000" />
<district name="大觀區(qū)" zipcode="246000" />
<district name="懷寧縣" zipcode="246000" />
<district name="潛山縣" zipcode="246000" />
<district name="宿松縣" zipcode="246000" />
<district name="太湖縣" zipcode="246000" />
<district name="桐城市" zipcode="246000" />
<district name="望江縣" zipcode="246000" />
<district name="宜秀區(qū)" zipcode="246000" />
<district name="迎江區(qū)" zipcode="246000" />
<district name="岳西縣" zipcode="246000" />
<district name="其他" zipcode="246000" />
</city>
......
XmlParserHandler類(lèi)代碼:
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<PrivinceModel> privinceModels ;
private List<CityModel> cityModels ;
private List<DistrictModel> districtModels ;
private PrivinceModel privinceModel ;
private DistrictModel districtModel ;
private CityModel cityModel ;
private String preTag ;
public List<PrivinceModel> getPrivinceModels() {
return privinceModels;
}
@Override
public void startDocument() throws SAXException {
super.startDocument();
privinceModels = new ArrayList<>() ;
Log.d(TAG, "startDocument: ------------------------------");
//當(dāng)讀到第一個(gè)標(biāo)簽的時(shí)候會(huì)觸發(fā)這個(gè)方法
}
@Override
public void startElement(String uri, String localName, String qName, Attributes attributes) throws SAXException {
super.startElement(uri, localName, qName, attributes);
//開(kāi)始解析節(jié)點(diǎn)
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 () {
//文檔解析結(jié)束
Log.d(TAG, "endDocument: --------------------------------------------");
}
public void characters (char[] ch, int start, int length) {
//保存節(jié)點(diǎn)內(nèi)容
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) {
//結(jié)束解析節(jié)點(diǎn)
Log.d(TAG, "endElement: ------------------------"+ uri + " " + localName + " " + qName);
}
}
- 調(diào)用新建類(lèi)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()) ;
地址選擇器實(shí)現(xiàn)
pickerView簡(jiǎn)介
這是一款仿iOS的PickerView控件,有時(shí)間選擇和選項(xiàng)選擇,并支持一二三級(jí)聯(lián)動(dòng),支持自定義樣式,3.x新版本的詳細(xì)特性如下:
有時(shí)間和選項(xiàng)這兩種選擇器
選項(xiàng)選擇器支持三級(jí)聯(lián)動(dòng)
時(shí)間選擇器支持起始和終止日期設(shè)定
支持“年,月,日,時(shí),分,秒”,“省,市,區(qū)”等選項(xiàng)的單位(label)顯示、隱藏和自定義。
支持自定義文字、顏色、文字大小等屬性
支持背景顏色更換,有夜間模式需求的問(wèn)題可以解決了
Item的文字長(zhǎng)度過(guò)長(zhǎng)時(shí),文字會(huì)自適應(yīng)縮放到Item的長(zhǎng)度,避免顯示不完全的問(wèn)題
——TimePickerView 時(shí)間選擇器,支持年月日時(shí)分,年月日,年月,時(shí)分等格式
——OptionsPickerView 選項(xiàng)選擇器,支持一,二,三級(jí)選項(xiàng)選擇,并且可以設(shè)置是否聯(lián)動(dòng)



- 詳細(xì)了解請(qǐng)戳github
pickerView代碼調(diào)用
下面是地址選擇器的代碼調(diào)用
OptionsPickerView pvOptions = new OptionsPickerView.Builder(this, new OptionsPickerView.OnOptionsSelectListener() {
@Override
public void onOptionsSelect(int options1, int option2, int options3 ,View v) {
//返回的分別是三個(gè)級(jí)別的選中位置
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("城市選擇")//標(biāo)題
.setSubCalSize(18)//確定和取消文字大小
.setTitleSize(20)//標(biāo)題文字大小
.setTitleColor(Color.BLACK)//標(biāo)題文字顏色
.setSubmitColor(Color.BLACK)//確定按鈕文字顏色
.setCancelColor(Color.BLACK)//取消按鈕文字顏色
.setTitleBgColor(Color.WHITE)//標(biāo)題背景顏色 Night mode
.setBgColor(Color.WHITE)//滾輪背景顏色 Night mode
.setContentTextSize(18)//滾輪文字大小
// .setLinkage(false)//設(shè)置是否聯(lián)動(dòng),默認(rèn)true
.setLabels("", "", "")//設(shè)置選擇的三級(jí)單位
.isCenterLabel(false) //是否只顯示中間選中項(xiàng)的label文字,false則每項(xiàng)item全部都帶有l(wèi)abel。
.setCyclic(false, false, false)//循環(huán)與否
.setSelectOptions(1, 1, 1) //設(shè)置默認(rèn)選中項(xiàng)
.setOutSideCancelable(false)//點(diǎn)擊外部dismiss default true
.isDialog(true)//是否顯示為對(duì)話(huà)框樣式
.build();
// Log.d("----" , "--------------"+county.get(1).get(1).get(1)) ;
pvOptions.setPicker(province, city , county);//添加數(shù)據(jù)源
pvOptions.show();
沒(méi)有什么要講了的,都在注釋里,這樣我們就可以調(diào)用好玩的地址選擇器啦。
其他部分沒(méi)有什么要說(shuō)的,就是簡(jiǎn)單布局,網(wǎng)絡(luò)申請(qǐng),處理信息,布拉布拉。完整代碼請(qǐng)戳頁(yè)首github地址。