編輯:關於Android編程
XML全稱為Extensible Markup Language, 意思是可擴展的標記語言,它是 SGML(標准通用標記語言)的一個子集。
XML語法上和HTML比較相似,但HTML中的元素是固定的,而XML的標簽是可以由用戶自定義的。
W3C在1998年2月發布1.0版本;
W3C在2004年2月發布1.1版本,但因為1.1版本不能向下兼容1.0版本,所以1.1沒有人用。同時,在2004年2月W3C又發布了1.0版本的第三版。我們要學習的還是1.0版本!!!
W3C是萬維網聯盟(World Wide Web Consortium)英文的縮寫,它成立於1994年10月,以開放論壇的方式來促進開發互通技術(包括規格、指南、軟件和工具),開發網絡的全部潛能。萬維網聯盟(W3C)從1994年成立以來,已發布了90多份Web技術規范,領導著Web技術向前發展。
W3C認為自身不是官方組織,因此將它正式發布的規范稱為推薦(建議)標准,意思是進一步標准化的建議,但是由於組織自身的權威性往往成為事實上的標准。
zhangSan 23male liSi 32female wangWu 55male
可以把xml文檔聲明看成是xml文檔說明。
最簡單的xml文檔聲明:< ?xml version=”1.0”? >
注意,XML是區別大小寫,這一點不同與HTML!
version屬性
用於說明當前xml文檔的版本,因為都是在用1.0,所以這個屬性值大家都寫1.0,version屬性是必須的;
encoding屬性
用於說明當前xml文檔使用的字符編碼集,xml解析器會使用這個編碼來解析xml文檔。encoding屬性是可選的,默認為UTF-8。注意,如果當前xml文檔使用的字符編碼集是gb2312,而encoding屬性的值為UTF-8,那麼一定會出錯的;
standalone屬性
用於說明當前xml文檔是否為獨立文檔,如果該屬性值為yes,表示當前xml文檔是獨立的,如果為no表示當前xml文檔不是獨立的,即依賴外部的文件。默認是yes
沒有xml文檔聲明的xml文檔,不是格式良好的xml文檔;
xml文檔聲明必須從xml文檔的1行1列開始。因為在xml文檔中有些字符是特殊的,不能使用它們作為文本數據。例如:不能使用“<”或“>”等字符作為文本數據,所以需要使用轉義字符來表示。
例如,你可能會說,其中第二個是a元素的文本內容,而不是一個元素的開始標簽,但xml解析器是不會明白你的意思的。
把修飾為<a>,這就OK了。

轉義字符都是以“&”開頭,以“;”結束。這與後面我們學習的實體是相同的。
當大量的轉義字符出現在xml文檔中時,會使xml文檔的可讀性大幅度降低。這時如果使用CDATA段就會好一些。
在CDATA段中出現的“<”、“>”、“””、“’”、“&”,都無需使用轉義字符。這可以提高xml文檔的可讀性
<a><![CDATA[<a>]]></a>
在CDATA段中不能包含“]]>”,即CDATA段的結束定界符
使用xml 作為數據交互的載體是Android 中非常重要的功能,比如天氣預報數據、短信備份數據、通訊錄數據都可以以xml 的格式通過網絡傳輸。
為了演示Xml 數據的操作,我模擬了一個短信備份的案例。
需求:界面如圖1-10 所示。上面是三個Button,前兩個分別對應兩種不同方式生成xml,第三個Button點擊後解析備份的xml 文件,然後將數據展現在下面的ScrollView 中。短信數據是模擬的假數據。

生成的xml 格式如下
5554我是內容<>0
5555我是內容<>1
編寫布局文件
//第一種方式生成xml
public void click1 (View view)throws Exception {
StringBuilder sb = new StringBuilder();
sb.append("");
sb.append("");
for (int i = 0; i < 50; i++) {
sb.append("");
sb.append("");
sb.append(5554 + i);
sb.append("");
sb.append("");
sb.append("我是短信內容" + i);
sb.append("");
sb.append("");
sb.append(" ");
}
sb.append(" ");
//使用系統提供的方法獲取文件輸出流
FileOutputStream fos = this.openFileOutput("info.xml", MODE_PRIVATE);
fos.write(sb.toString().getBytes());
fos.close();
}
上面的代碼雖然也可以生成xml 文件,但是無法對特殊字符進行處理,比如如果短信內容包含“
/**
* 第二種方式生成xml
* 使用Android 提供的API
*/
public void click2 (View view)throws Exception {
//在data 目錄中創建info2.xml 文件,獲取輸出流
FileOutputStream fos = openFileOutput("info2.xml", MODE_PRIVATE);
//通過Xml 類創建一個Xml 序列化器
XmlSerializer serializer = Xml.newSerializer();
//給序列化器設置輸出流和輸出流編碼
serializer.setOutput(fos, "utf-8");
/**
* 讓序列化器開發寫入xml 的頭信息,其本質是寫入內容:
* ""
*/
serializer.startDocument("utf-8", true);
/**
* 開始寫入smses 標簽,
* 第一個參數是該標簽的命名空間, 這裡不需要
*/
serializer.startTag(null, "smses");
for (int i = 0; i < 50; i++) {
//開始sms 標簽
serializer.startTag(null, "sms");
//開始address 標簽
serializer.startTag(null, "address");
//在address 標簽中間寫入文本
serializer.text("" + (5554 + i));
//結束address 標簽
serializer.endTag(null, "address");
//開始body 標簽
serializer.startTag(null, "body");
//在body 標簽中間寫入文本
serializer.text("我是內容<>" + i);
//結束body 標簽
serializer.endTag(null, "body");
serializer.startTag(null, "time");
serializer.text(new Date().getTime() + "");
serializer.endTag(null, "time");
//結束sms 標簽
serializer.endTag(null, "sms");
}
//結束smses 標簽
serializer.endTag(null, "smses");
//結束文檔
serializer.endDocument();
fos.close();
}
使用XmlSerializer 生成xml 文件是推薦的方式,因為該api 內部已經實現了對特殊字符的處理
asserts 資源目錄中的文件只能讀不能寫,多用於隨apk 一起發布的固定不變的數據,比如可以將國內所有的城市列表放在裡面。
這裡將生成的info2.xml 放到asserts 目錄中,然後讀取、解析、展現
//使用pull 解析xml 數據
public void click3(View v) throws Exception {
/**
* 將解析出來的數據封裝在Sms 中,然後保存到ArrayList 中
* Sms 是自定義的一個JavaBean
*/
ArrayList smses = null;
Sms sms = null;
//調用父類提供的getAssets()方法獲取AssertManager 對象
AssetManager assetManager = getAssets();
//使用assetManager 的open 方法直接獲取輸入流對象
InputStream inputStream = assetManager.open("info2.xml");
//通過Xml 的靜態方法獲取Xml 解析器
XmlPullParser parser = Xml.newPullParser();
//設置輸入流和編碼
parser.setInput(inputStream, "utf-8");
//獲取事件類型
int event = parser.next();
//如果沒有解析到文檔的結尾,則循環解析
while (event != XmlPullParser.END_DOCUMENT) {
//獲取當前解析到的標簽名稱
String tagName = parser.getName();
//如果是“開始標簽”事件
if (event == XmlPullParser.START_TAG) {
//判斷當前解析到的開始標簽是哪個
if ("smses".equals(tagName)) {
smses = new ArrayList();
} else if ("sms".equals(tagName)) {
sms = new Sms();
} else if ("address".equals(tagName)) {
sms.setAddress(parser.nextText());
} else if ("body".equals(tagName)) {
sms.setBody(parser.nextText());
} else if ("time".equals(tagName)) {
sms.setTime(parser.nextText());
}
//如果是“結束標簽”事件
} else if (event == XmlPullParser.END_TAG) {
if ("sms".equals(tagName)) {
//如果是sms 結尾,則將創建的sms 對象添加到集合中
smses.add(sms);
}
}
//繼續獲取下一個事件
event = parser.next();
}
inputStream.close();
//將數據展示到界面
showSms(smses);
}
/**
* 將短信顯示到TextView 中
*/
private void showSms(ArrayList smses) {
StringBuilder sb = new StringBuilder();
for (Sms s : smses) {
sb.append(s.toString() + "\n");
}
tv_sms.setText(sb.toString());
}
Pull 解析器的運行方式與SAX 解析器相似,都屬於事件驅動模式。它提供了類似的事件,如:開始元素和結束元素事件,使用parser.next()可以進入下一個元素並觸發相應事件。事件將作為數值代碼被發送,因此可以使用一個switch 對感興趣的事件進行處理。當元素開始解析時,調用parser.nextText()方法可以獲
取下一個Text 類型元素的值。
SAX 解析器的工作方式是自動將事件推入事件處理器進行處理,因此你不能控制事件的處理主動結束;而Pull 解析器的工作方式為允許你的應用程序代碼主動從解析器中獲取事件,正因為是主動獲取事件,因此可以在滿足了需要的條件後不再獲取事件,結束解析

新聞數據
熱烈祝賀黑馬52期平均薪水突破13k 15687 http://192.168.1.100:8080/images/6.jpg
凶手是死者同事,維護死者代碼時完全看不懂而痛下殺手 16359 http://192.168.1.100:8080/images/7.jpg
凶手是一名程序員,因死者對項目需求頻繁改動而痛下殺手 14112 http://192.168.1.100:8080/images/7.jpg
最高法駁回360上訴, 維持一審宣判. 6427 http://192.168.1.100:8080/images/1.jpg
市民: 因霧霾起訴環保局; 公務員談"緊日子": 堅決不出去. 681 http://192.168.1.100:8080/images/2.jpg
外文局: 國際民眾認可中國大國地位;法院: "流量清零"未侵權. 1359 http://192.168.1.100:8080/images/3.jpg
放假時我醒了不代表我起床了, 如今我起床了不代表我醒了! 11616 http://192.168.1.100:8080/images/4.jpg
"媽, 我在東莞被抓, 要2萬保釋金, 快匯錢到xxx!" 10339 http://192.168.1.100:8080/images/5.jpg
少壯不努力,老大做IT 14612 http://192.168.1.100:8080/images/8.jpg
問君能有幾多愁,恰似調完代碼改需求 13230 http://192.168.1.100:8080/images/8.jpg
覺得我帥的人工資一般都比較高 9928 http://192.168.1.100:8080/images/8.jpg
市民: 因霧霾起訴環保局; 公務員談"緊日子": 堅決不出去. 681 http://192.168.1.100:8080/images/2.jpg
外文局: 國際民眾認可中國大國地位;法院: "流量清零"未侵權. 1359 http://192.168.1.100:8080/images/3.jpg
布局文件
ListView的item布局
實體bean
public class News {
private String title;
private String detail;
private String comment;
private String imageUrl;
@Override
public String toString() {
return "News [title=" + title + ", detail=" + detail + ", comment="
+ comment + ", imageUrl=" + imageUrl + "]";
}
public String getTitle() {
return title;
}
public void setTitle(String title) {
this.title = title;
}
public String getDetail() {
return detail;
}
public void setDetail(String detail) {
this.detail = detail;
}
public String getComment() {
return comment;
}
public void setComment(String comment) {
this.comment = comment;
}
public String getImageUrl() {
return imageUrl;
}
public void setImageUrl(String imageUrl) {
this.imageUrl = imageUrl;
}
}
實現代碼
public class MainActivity extends Activity {
List newsList;
Handler handler = new Handler(){
public void handleMessage(android.os.Message msg) {
ListView lv = (ListView) findViewById(R.id.lv);
lv.setAdapter(new MyAdapter());
}
};
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
getNewsInfo();
// ListView lv = (ListView) findViewById(R.id.lv);
// //要保證在設置適配器時,新聞xml文件已經解析完畢了
// lv.setAdapter(new MyAdapter());
}
class MyAdapter extends BaseAdapter{
//得到模型層中元素的數量,用來確定listview需要有多少個條目
@Override
public int getCount() {
// TODO Auto-generated method stub
return newsList.size();
}
@Override
//返回一個View對象,作為listview的條目顯示至界面
public View getView(int position, View convertView, ViewGroup parent) {
News news = newsList.get(position);
View v = null;
ViewHolder mHolder;
if(convertView == null){
v = View.inflate(MainActivity.this, R.layout.item_listview, null);
mHolder = new ViewHolder();
//把布局文件中所有組件的對象封裝至ViewHolder對象中
mHolder.tv_title = (TextView) v.findViewById(R.id.tv_title);
mHolder.tv_detail = (TextView) v.findViewById(R.id.tv_detail);
mHolder.tv_comment = (TextView) v.findViewById(R.id.tv_comment);
mHolder.siv = (SmartImageView) v.findViewById(R.id.iv);
//把ViewHolder對象封裝至View對象中
v.setTag(mHolder);
}
else{
v = convertView;
mHolder = (ViewHolder) v.getTag();
}
//給三個文本框設置內容
mHolder.tv_title.setText(news.getTitle());
mHolder.tv_detail.setText(news.getDetail());
mHolder.tv_comment.setText(news.getComment() + "條評論");
//給新聞圖片imageview設置內容
mHolder.siv.setImageUrl(news.getImageUrl());
return v;
}
class ViewHolder{
//條目的布局文件中有什麼組件,這裡就定義什麼屬性
TextView tv_title;
TextView tv_detail;
TextView tv_comment;
SmartImageView siv;
}
@Override
public Object getItem(int position) {
return null;
}
@Override
public long getItemId(int position) {
return 0;
}
}
private void getNewsInfo() {
Thread t = new Thread(){
@Override
public void run() {
String path = "http://192.168.13.13:8080/news.xml";
try {
URL url = new URL(path);
HttpURLConnection conn = (HttpURLConnection) url.openConnection();
conn.setRequestMethod("GET");
conn.setConnectTimeout(5000);
conn.setReadTimeout(5000);
//發送http GET請求,獲取相應碼
if(conn.getResponseCode() == 200){
InputStream is = conn.getInputStream();
//使用pull解析器,解析這個流
parseNewsXml(is);
}
} catch (Exception e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
};
t.start();
}
private void parseNewsXml(InputStream is) {
XmlPullParser xp = Xml.newPullParser();
try {
xp.setInput(is, "utf-8");
//對節點的事件類型進行判斷,就可以知道當前節點是什麼節點
int type = xp.getEventType();
News news = null;
while(type != XmlPullParser.END_DOCUMENT){
switch (type) {
case XmlPullParser.START_TAG:
if("newslist".equals(xp.getName())){
newsList = new ArrayList();
}
else if("news".equals(xp.getName())){
news = new News();
}
else if("title".equals(xp.getName())){
String title = xp.nextText();
news.setTitle(title);
}
else if("detail".equals(xp.getName())){
String detail = xp.nextText();
news.setDetail(detail);
}
else if("comment".equals(xp.getName())){
String comment = xp.nextText();
news.setComment(comment);
}
else if("image".equals(xp.getName())){
String image = xp.nextText();
news.setImageUrl(image);
}
break;
case XmlPullParser.END_TAG:
if("news".equals(xp.getName())){
newsList.add(news);
}
break;
}
//解析完當前節點後,把指針移動至下一個節點,並返回它的事件類型
type = xp.next();
}
//發消息,讓主線程設置listview的適配器,如果消息不需要攜帶數據,可以發送空消息
handler.sendEmptyMessage(1);
// for (News n : newsList) {
// System.out.println(n.toString());
// }
} catch (Exception e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
Android 四大組件之Service 的生命周期和使用
Service簡介:Service 是Android的四大組件之一,一般用於沒有UI界面,長期執行的後台任務,即使程序退出時,後台任務還在執行。比如:音樂播放。Servi
Android Activity的啟動過程
每天看郭神的公眾號文章已經成了我的一個習慣,前段時間看到一篇文章,ActivityThread的main()方法究竟做了什麼工作?main方法代碼並不長,但行行珠玑。我也
Android實現短信發送功能
本文實例實現了兩個模擬器之間短信的發送功能,分享給大家供大家參考,具體實現內容如下1.編輯String.xml文件內容為:<?xml version=”1.
Android NDK環境搭建與簡單實例
一、NDK與JNI簡介 NDK全稱為native development kit本地語言(C&C++)開發包。而對應的是經常接觸的Android-SDK