本項目來自菜鳥窩佑菩,有興趣者點擊http://www.cniao5.com/course/
項目已經(jīng)做完绞幌,
https://github.com/15829238397/CN5E-shop
仿京東商城系列0------項目簡介
仿京東商城系列1------fragmentTabHost實現(xiàn)底部導航欄
仿京東商城系列2------自定義toolbar
仿京東商城系列3------封裝Okhttp
仿京東商城系列4------輪播廣告條
仿京東商城系列5------商品推薦欄
仿京東商城系列6------下拉刷新上拉加載的商品列表
仿京東商城系列7------商品分類頁面
仿京東商城系列8------自定義的數(shù)量控制器
仿京東商城系列9------購物車數(shù)據(jù)存儲器實現(xiàn)
仿京東商城系列10------添加購物車,管理購物車功能實現(xiàn)
仿京東商城系列11------商品排序功能以及布局切換實現(xiàn)(Tablayout)
仿京東商城系列12------商品詳細信息展示(nativie與html交互)
仿京東商城系列13------商品分享(shareSDK)
仿京東商城系列14------用戶登錄以及app登錄攔截
仿京東長城系列15------用戶注冊,SMSSDK集成
仿京東商城系列16------支付SDK集成
仿京東商城系列17------支付功能實現(xiàn)
仿京東商城系列18------xml文件讀刃呱帧(地址選擇器)
仿京東商城系列19------九宮格訂單展示
仿京東商城系列20------終章
前言
我們接著上一更的內(nèi)容畏浆,上一更我們集成并使用了支付SDK完成了模擬支付。但我們的訂單編輯頁面地址與收貨人信息一欄還是空白,今天我們要做的就是填充這個空白。效果圖如下:
內(nèi)容
補充新知識
xml文件讀取
解析方式
1、DOM解析器
DOM(Document Object Model) 是一種用于XML文檔的對象模型,可用于直接訪問XML文檔的各個部分胶背。它是一次性全部將內(nèi)容加載在內(nèi)存中,生成一個樹狀結(jié)構(gòu),它沒有涉及回調(diào)和復雜的狀態(tài)管理。 缺點是加載大文檔時效率低下,所以一般在解析大文檔時不建議使用DOM解析岳服。
分析該結(jié)構(gòu)通常需要加載整個文檔和構(gòu)造樹形結(jié)構(gòu)贫母,然后才可以檢索和更新節(jié)點信息。Android完全支持DOM 解析趾断。利用DOM中的對象脐帝,可以對XML文檔進行讀取疚顷、搜索届垫、修改妄迁、添加和刪除等操作。
DOM的工作原理:使用DOM對XML文件進行操作時,首先要解析文件流妻,將文件分為獨立的元素、屬性和注釋等,然后以節(jié)點樹的形式在內(nèi)存中對XML文件進行表示浑度,就可以通過節(jié)點樹訪問文檔的內(nèi)容,并根據(jù)需要修改文檔横漏。
常用的DOM的接口和類:
Document:該接口定義分析并創(chuàng)建DOM文檔的一系列方法,它是文檔樹的根二蓝,是操作DOM的基礎。
Node:該接口提供處理并獲取節(jié)點和子節(jié)點值的方法。
Element:該接口繼承Node接口,提供了獲取炬藤、修改XML元素名字和屬性的方法并闲。
NodeList:提供獲得節(jié)點個數(shù)和當前節(jié)點的方法溜徙。這樣就可以迭代地訪問各個節(jié)點九巡。
DOMParser:該類是Apache的Xerces中的DOM解析器類疏日,可直接解析XML文件。
2宾肺、SAX解析
SAX(Simple API for XML) 使用流式處理的方式,它并不記錄所讀內(nèi)容的相關(guān)信息。它是一種以事件為驅(qū)動的XML API,解析速度快熄求,占用內(nèi)存少渣玲。使用回調(diào)函數(shù)來實現(xiàn)。 缺點是因為以事件為驅(qū)動的它不能回退弟晚。
它的核心是事件處理模式忘衍,主要是圍繞著事件源以及事件處理器來工作的卿城。當事件源產(chǎn)生事件后拣凹,調(diào)用事件處理器相應的處理方法节腐,一個事件就可以得到處理。在事件源調(diào)用事件處理器中特定方法的時候,還要傳遞給事件處理器相應事件的狀態(tài)信息徽职,這樣事件處理器才能夠根據(jù)提供的事件信息來決定自己的行為怠蹂。
SAX的工作原理:SAX會順序掃描文檔剧蹂,在掃描到文檔(document)開始與結(jié)束爆安、元素(element)開始與結(jié)束、元素內(nèi)容(characters)等時通知事件處理方法怀偷,事件處理方法進行相應處理家厌,然后繼續(xù)掃描,指導文檔掃描結(jié)束椎工。
常用的SAX接口和類:
Attrbutes:用于得到屬性的個數(shù)饭于、名字和值。
ContentHandler:定義與文檔本身關(guān)聯(lián)的事件(例如维蒙,開始和結(jié)束標記)掰吕。大多數(shù)應用程序都注冊這些事件木西。
DTDHandler:定義與DTD關(guān)聯(lián)的事件畴栖。它沒有定義足夠的事件來完整地報告DTD。如果需要對DTD進行語法分析八千,請使用可選的DeclHandler吗讶。
DeclHandler是SAX的擴展。不是所有的語法分析器都支持它恋捆。
EntityResolver:定義與裝入實體關(guān)聯(lián)的事件照皆。只有少數(shù)幾個應用程序注冊這些事件。
ErrorHandler:定義錯誤事件沸停。許多應用程序注冊這些事件以便用它們自己的方式報錯膜毁。
DefaultHandler:它提供了這些接LI的缺省實現(xiàn)。在大多數(shù)情況下愤钾,為應用程序擴展DefaultHandler并覆蓋相關(guān)的方法要比直接實現(xiàn)一個接口更容易瘟滨。
下面是部分說明:
部分常用方法說明
所以,我們通常要使用XmlReader和DefaultHandler配合起來解析xml文檔能颁。
SAX的解析流程:
startDocument --> startElement --> characters --> endElement --> endDocument
3杂瘸、pull解析
Pull內(nèi)置于Android系統(tǒng)中。也是官方解析布局文件所使用的方式伙菊。Pull與SAX有點類似败玉,都提供了類似的事件,如開始元素和結(jié)束元素镜硕。不同的是运翼,SAX的事件驅(qū)動是回調(diào)相應方法,需要提供回調(diào)的方法兴枯,而后在SAX內(nèi)部自動調(diào)用相應的方法血淌。而Pull解析器并沒有強制要求提供觸發(fā)的方法。因為他觸發(fā)的事件不是一個方法财剖,而是一個數(shù)字悠夯。它使用方便,效率高峰伙。Android官方推薦開發(fā)者們使用Pull解析技術(shù)疗疟。Pull解析技術(shù)是第三方開發(fā)的開源技術(shù),它同樣可以應用于JavaSE開發(fā)瞳氓。
pull返回的常量:
讀取到xml的聲明返回 START_DOCUMENT;
讀取到xml的結(jié)束返回 END_DOCUMENT ;
讀取到xml的開始標簽返回 START_TAG;
讀取到xml的結(jié)束標簽返回 END_TAG;
讀取到xml的文本返回 TEXT;
pull的工作原理:pull提供了開始元素和結(jié)束元素策彤。當某個元素開始時,我們可以調(diào)用parser.nextText從XML文檔中提取所有字符數(shù)據(jù)匣摘。當解釋到一個文檔結(jié)束時店诗,自動生成EndDocument事件。
常用的XML pull的接口和類:
XmlPullParser:XML pull解析器是一個在XMLPULL VlAP1中提供了定義解析功能的接口音榜。
XmlSerializer:它是一個接口庞瘸,定義了XML信息集的序列。
XmlPullParserFactory:這個類用于在XMPULL V1 API中創(chuàng)建XML Pull解析器赠叼。
XmlPullParserException:拋出單一的XML pull解析器相關(guān)的錯誤擦囊。
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實現(xiàn)XML解析 :
MyHandler myHandler=new MyHandler0眼五;
android.util.Xm1.parse(url.openC0nnection().getlnputStream(),Xml.Encoding.UTF-8彤灶,myHandler)看幼;
代碼講解
了解完概念,我們就可以著手解析xml文件了幌陕。接下來我來講述以下解析xml文件的步驟诵姜。
- 將xml文件放在main->assets目錄下。
- 新建一個類XmlParserHandler繼承DefaultHandler苞轿,并實現(xiàn)相關(guān)方法茅诱。代碼如下:
xml文件:
<root>
<province name="安徽省">
<city name="安慶市">
<district name="樅陽縣" 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類代碼:
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: ------------------------------");
//當讀到第一個標簽的時候會觸發(fā)這個方法
}
@Override
public void startElement(String uri, String localName, String qName, Attributes attributes) throws SAXException {
super.startElement(uri, localName, qName, attributes);
//開始解析節(jié)點
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é)點內(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é)點
Log.d(TAG, "endElement: ------------------------"+ uri + " " + localName + " " + qName);
}
}
- 調(diào)用新建類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()) ;
地址選擇器實現(xiàn)
pickerView簡介
這是一款仿iOS的PickerView控件,有時間選擇和選項選擇搬卒,并支持一二三級聯(lián)動,支持自定義樣式摆寄,3.x新版本的詳細特性如下:
有時間和選項這兩種選擇器
選項選擇器支持三級聯(lián)動
時間選擇器支持起始和終止日期設定
支持“年微饥,月古戴,日肃续,時始锚,分瞧捌,秒”殿怜,“省赠法,市砖织,區(qū)”等選項的單位(label)顯示新锈、隱藏和自定義妹笆。
支持自定義文字、顏色窟坐、文字大小等屬性
支持背景顏色更換,有夜間模式需求的問題可以解決了
Item的文字長度過長時徙菠,文字會自適應縮放到Item的長度,避免顯示不完全的問題
——TimePickerView 時間選擇器脸秽,支持年月日時分,年月日片酝,年月练湿,時分等格式
——OptionsPickerView 選項選擇器,支持一篡诽,二,三級選項選擇,并且可以設置是否聯(lián)動
- 詳細了解請戳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) {
//返回的分別是三個級別的選中位置
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)//設置是否聯(lián)動,默認true
.setLabels("", "", "")//設置選擇的三級單位
.isCenterLabel(false) //是否只顯示中間選中項的label文字,false則每項item全部都帶有l(wèi)abel啃憎。
.setCyclic(false, false, false)//循環(huán)與否
.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);//添加數(shù)據(jù)源
pvOptions.show();
沒有什么要講了的羡藐,都在注釋里,這樣我們就可以調(diào)用好玩的地址選擇器啦仆嗦。
其他部分沒有什么要說的辉阶,就是簡單布局谆甜,網(wǎng)絡申請,處理信息,布拉布拉。完整代碼請戳頁首github地址掠河。