大家好,在这篇中文章中我们继续探讨XML布局文件在Activity自动生成代码。可能大家对于这个表述没有一个直观的认识,我先举个简单的例子。
倘若某一个Activity的XML布局文件(省略其他不必要的代码)为:
<TextView
...
android:id="@+id/testTextView"
...
/>
那么程序应该自动提供以下代码:
private TextView testTextView;
testTextView = (TextView)findViewById(R.id.testTextView);
注意:在这里我们默认控件句柄的名称与其在XML对应控件的id是一样的。
如果控件是EditText 、 ImageView或者是其它的控件,程序自动生成代码的逻辑应该是一样的。
但是如果是后缀以Button结尾的控件,显然自动生成以上代码是不够的,我们还希望能生成其控件注册监听器以及在监听器中处理事件的代码,废话少说,还是先举个例子:
<Button
...
android:id="@+id/testButton"
...
/>
预期程序生成代码:
private Button testButton;
testButton = (Button)findViewById(R.id.testButton);
testButton.setOnClickListener(mOnClickListener);
OnClickListener mOnClickListener = new OnClickListener() {
public void onClick(View v) {
switch (v.getId()) {
case R.id.testButton:
break;
}
}
};
看到这里大家应该清楚xml文件自动生成代码的意思了吧。这一篇文章的主题是SAX解析,但是写了一大堆还没提到它,别急现在就主要介绍它了。
首先肯定有读者会提出两个问题,我先在这里说明一下:
1.为什么要用到SAX解析?
答:SAX解析是解析XML一种技术,我们解析XML文档主要的目的就是得到XML文档中各个控件的id,因为在程序自动生成的代码中要用到它。
如:xxx = (控件类型)findViewById(R.id.xxx)。
(题外话:曾经一开始我用正则表达式去匹配出控件的id,无论怎么写总是有一些问题,后来有同事提醒我直接解析XML)
2.为什么用使用SAX解析而不其他的解析技术?
答:Java解析XML确实有几种解析技术,不过刚开始我就使用SAX解析,没有什么特别的原因。
简单的介绍一下SAX解析的相关知识:
SAX的工作原理简单地说就是对文档进行顺序扫描,当扫描到文档(document)开始与结束、元素(element)开始与结束、文档(document)结束等地方时通知事件处理函数,由事件处理函数做相应动作,然后继续同样的扫描,直至文档结束。
SAX解析文档过程举例
对于一个XML文档举例来说 Hello,World!
其解析的过程为:
1.start document
2.start element:doc......
3.start element:para.....
4.characters:Hello,World!
5.end element:para......
6.end element;doc......
7.end document
对于解析过程中的每一步都会有事件发生,都会触发相应接口中的事件处理程序。
经过简单的介绍,想必大家对SAX有了一定的了解。接下来继续深入,举一个实际的例子,方便新手有更直观的了解:
测试XML文档:
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:orientation="vertical" >
<Button
android:id="@+id/testButton"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:text="Button" />
<TextView
android:id="@+id/testTextView"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:text="TextView" android:textSize="40dp"/>
事件处理程序:
package org.lalalu;
import java.util.ArrayList;
import java.util.List;
import org.xml.sax.Attributes;
import org.xml.sax.SAXException;
import org.xml.sax.helpers.DefaultHandler;
public class MyContentHandler extends DefaultHandler {
private List widgetList;
// 开始解析XML文档,在这里初始化变量
@Override
public void startDocument() throws SAXException {
widgetList = new ArrayList();
}
// 文档解析结束,并输出解析XML文档后的结果
@Override
public void endDocument() throws SAXException {
for (String str : widgetList) {
System.out.println(str);
}
}
// 解析到xml文件的元素开始标记的时候会调用这个函数
@Override
public void startElement(String uri, String localName, String qName,
Attributes attributes) throws SAXException {
for (int i = 0, len = attributes.getLength(); i < len; i++) {
String str = attributes.getValue(i).toString();
if (attributes.getLocalName(i).equals("android:id")
&& attributes.getValue(i).toString().startsWith("@+id")) {
widgetList
.add(str.substring(str.indexOf('/') + 1, str.length()));
}
}
}
// 解析到xml文件的元素结束标记的时候会调用这个函数
@Override
public void endElement(String uri, String localName, String qName)
throws SAXException {
super.endElement(uri, localName, qName);
}
// 解析到xml文件的元素值的时候会调用这个函数
@Override
public void characters(char[] ch, int start, int length)
throws SAXException {
super.characters(ch, start, length);
}
}
使用类:
package org.lalalu;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.io.InputStream;
import javax.xml.parsers.ParserConfigurationException;
import javax.xml.parsers.SAXParser;
import javax.xml.parsers.SAXParserFactory;
import org.xml.sax.SAXException;
public class ReaderSax {
public static void main(String[] args) {
// 得到SAX解析器的工厂实例
SAXParserFactory saxfa = SAXParserFactory.newInstance();
try {
// 从SAX工厂实例中获得SAX解析器
SAXParser saxparser = saxfa.newSAXParser();
// 把文档转换成流
InputStream it = new FileInputStream(
"C:/Documents and Settings/Administrator/桌面/test.xml");
saxparser.parse(it, new MyContentHandler());
} catch (ParserConfigurationException e) {
e.printStackTrace();
} catch (SAXException e) {
e.printStackTrace();
} catch (FileNotFoundException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
}
}
运行结果: testButton testTextView
以上例子下载链接:
总结:到现在为止我们已经获取到了XML文档中控件的id,但是离当初设想自动生成的代码还有一段距离。下一篇我们将终结这一系列的文章,并提供完整的代码和讲解。