rxandroid dom解析xml支持xml解析库吗

详细解析RxAndroid的使用方式
详细解析RxAndroid的使用方式
发布时间: 17:50:23
编辑:www.fx114.net
本篇文章主要介绍了"详细解析RxAndroid的使用方式",主要涉及到详细解析RxAndroid的使用方式方面的内容,对于详细解析RxAndroid的使用方式感兴趣的同学可以参考一下。
欢迎Follow我的, 关注我的. 其余参考.
是RxJava的扩展, 可以优雅地处理异步请求. 以前的讲述过一些, 这次再补充些内容, 熟悉RxAndroid的使用方法.
本文源码的GitHub
(1) 链式表达式的使用方式.
(2) Lambda的应用.
(3) Rx处理网络请求.
(4) 线程自动管理, 防止内存泄露.
(5) RxBinding绑定控件的异步事件.
当然, 从一个崭新的HelloWorld项目开始.
添加Gradle配置.
compile 'com.jakewharton:butterknife:7.0.1'
compile 'io.reactivex:rxandroid:1.1.0'
compile 'io.reactivex:rxjava:1.1.0'
RxAndroid是本文的核心依赖, 同时添加RxJava. 还有ButterKnife注解库.
Lambda表达式, 是写出优雅代码的关键, .
id &me.tatarka.retrolambda& version &3.2.4&
compileOptions {
sourceCompatibility JavaVersion.VERSION_1_8
targetCompatibility JavaVersion.VERSION_1_8
Gradle 2.1+以上, 配置非常简单, 添加一个plugin和一个Java1.8兼容即可.
从主MainActivity跳转至SimpleActivity.
wangchenlong
public class MainActivity extends AppCompatActivity {
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
public void gotoSimpleModule(View view) {
startActivity(new Intent(this, SimpleActivity.class));
public void gotoMoreModule(View view) {
startActivity(new Intent(this, MoreActivity.class));
public void gotoLambdaModule(View view) {
startActivity(new Intent(this, LambdaActivity.class));
public void gotoNetworkModule(View view) {
startActivity(new Intent(this, NetworkActivity.class));
public void gotoSafeModule(View view) {
startActivity(new Intent(this, SafeActivity.class));
在SimpleActivity中, 创建一个观察者, 收到字符串的返回.
Observable.OnSubscribe mObservableAction = new Observable.OnSubscribe&String&() {
@Override public void call(Subscriber&? super String& subscriber) {
subscriber.onNext(sayMyName());
subscriber.onCompleted();
private String sayMyName() {
return &Hello, I am your friend, Spike!&;
创建两个订阅者, 使用字符串输出信息.
Subscriber&String& mTextSubscriber = new Subscriber&String&() {
@Override public void onCompleted() {
@Override public void onError(Throwable e) {
@Override public void onNext(String s) {
mTvText.setText(s);
Subscriber&String& mToastSubscriber = new Subscriber&String&() {
@Override public void onCompleted() {
@Override public void onError(Throwable e) {
@Override public void onNext(String s) {
Toast.makeText(SimpleActivity.this, s, Toast.LENGTH_SHORT).show();
在页面中, 观察者接收信息, 发送至主线程AndroidSchedulers.mainThread(), 再传递给订阅者, 由订阅者最终处理消息. 接收信息可以是同步, 也可以是异步.
@Override protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_simple);
ButterKnife.bind(this);
@SuppressWarnings(&unchecked&)
Observable&String& observable = Observable.create(mObservableAction);
observable.observeOn(AndroidSchedulers.mainThread());
observable.subscribe(mTextSubscriber);
observable.subscribe(mToastSubscriber);
最基础的RxAndroid使用.
我们已经熟悉了初步的使用方式, 在接着学习一些其他方法, 如
just: 获取输入数据, 直接分发, 更加简洁, 省略其他回调.
from: 获取输入数组, 转变单个元素分发.
map: 映射, 对输入数据进行转换, 如大写.
flatMap: 增大, 本意就是增肥, 把输入数组映射多个值, 依次分发.
reduce: 简化, 正好相反, 把多个数组的值, 组合成一个数据.
来看看这个示例, 设置两个不同类型数组, 作为输入源, 根据不同情况分发数据.
public class MoreActivity extends Activity {
@Bind(R.id.simple_tv_text) TextView mTvT
final String[] mManyWords = {&Hello&, &I&, &am&, &your&, &friend&, &Spike&};
final List&String& mManyWordList = Arrays.asList(mManyWords);
private Action1&String& mTextViewAction = new Action1&String&() {
@Override public void call(String s) {
mTvText.setText(s);
private Action1&String& mToastAction = new Action1&String&() {
@Override public void call(String s) {
Toast.makeText(MoreActivity.this, s, Toast.LENGTH_SHORT).show();
private Func1&List&String&, Observable&String&& mOneLetterFunc = new Func1&List&String&, Observable&String&&() {
@Override public Observable&String& call(List&String& strings) {
return Observable.from(strings);
private Func1&String, String& mUpperLetterFunc = new Func1&String, String&() {
@Override public String call(String s) {
return s.toUpperCase();
private Func2&String, String, String& mMergeStringFunc = new Func2&String, String, String&() {
@Override public String call(String s, String s2) {
return String.format(&%s %s&, s, s2);
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_simple);
ButterKnife.bind(this);
Observable&String& obShow = Observable.just(sayMyName());
obShow.observeOn(AndroidSchedulers.mainThread())
.map(mUpperLetterFunc).subscribe(mTextViewAction);
Observable&String& obMap = Observable.from(mManyWords);
obMap.observeOn(AndroidSchedulers.mainThread())
.map(mUpperLetterFunc).subscribe(mToastAction);
Observable.just(mManyWordList)
.observeOn(AndroidSchedulers.mainThread())
.flatMap(mOneLetterFunc)
.reduce(mMergeStringFunc)
.subscribe(mToastAction);
private String sayMyName() {
return &Hello, I am your friend, Spike!&;
这次简化调用代码, 因为有时候我们对异常并不是很关心,
只要能catch异常即可, 因此流仅仅关注真正需要的部分.
输入字符串, 变换大写, 输出至控件中显示.
Observable&String& obShow = Observable.just(sayMyName());
obShow.observeOn(AndroidSchedulers.mainThread())
.map(mUpperLetterFunc).subscribe(mTextViewAction);
just可以非常简单的获取任何数据, 分发时, 选择使用的线程.
map是对输入数据加工, 转换类型, 输入Func1, 准换大写字母.
Func1代表使用一个参数的函数, 前面是参数, 后面是返回值.
Action1代表最终动作, 因而不需要返回值, 并且一个参数.
输入数组, 单独分发数组中每一个元素, 转换大写, 输入Toast连续显示.
Observable&String& obMap = Observable.from(mManyWords);
obMap.observeOn(AndroidSchedulers.mainThread())
.map(mUpperLetterFunc).subscribe(mToastAction);
from是读取数组中的值, 每次单独分发, 并分发多次, 其余类似.
输入数组, 映射为单独分发, 并组合到一起, 集中显示.
Observable.just(mManyWordList)
.observeOn(AndroidSchedulers.mainThread())
.flatMap(mOneLetterFunc)
.reduce(mMergeStringFunc)
.subscribe(mToastAction);
这次是使用just分发数组, 则分发数据就是数组, 并不是数组中的元素.
flatMap把数组转换为单独分发, Func1内部使用from拆分数组.
reduce把单独分发数据集中到一起, 再统一分发, 使用Func2.
最终使用Action1显示获得数据. 本次代码也更加简洁.
由此我们可以观察到, Rx的写法可以是多种多样, 合理的写法会更加优雅.
Lambda表达式和Rx非常契合, 可以省略大量的内部类, 如Func和Action.
我们把上个示例, 用Lambda再写一次, 功能相同.
public class LambdaActivity extends Activity {
@Bind(R.id.simple_tv_text) TextView mTvT
final String[] mManyWords = {&Hello&, &I&, &am&, &your&, &friend&, &Spike&};
final List&String& mManyWordList = Arrays.asList(mManyWords);
@Override protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_simple);
ButterKnife.bind(this);
Observable&String& obShow = Observable.just(sayMyName());
obShow.observeOn(AndroidSchedulers.mainThread())
.map(String::toUpperCase).subscribe(mTvText::setText);
Observable&String& obMap = Observable.from(mManyWords);
obMap.observeOn(AndroidSchedulers.mainThread())
.map(String::toUpperCase)
.subscribe(this::showToast);
Observable.just(mManyWordList)
.observeOn(AndroidSchedulers.mainThread())
.flatMap(Observable::from)
.reduce(this::mergeString)
.subscribe(this::showToast);
private String sayMyName() {
return &Hello, I am your friend, Spike!&;
private void showToast(String s) {
Toast.makeText(LambdaActivity.this, s, Toast.LENGTH_SHORT).show();
private String mergeString(String s1, String s2) {
return String.format(&%s %s&, s1, s2);
这次没有使用常规的Lambda表达式, 而是更简单的方法引用(Method References).
方法引用: 方法参数和返回值与Lambda表达式相同时, 使用方法名代替.
4. 网络请求
是网络请求库, 刚推出2.0版本. Rx的一个核心应用就是处理异步网络请求, 结合Retrofit, 会更加方便和简洁.
compile 'com.android.support:recyclerview-v7:23.1.1'
compile 'com.squareup.retrofit:retrofit:2.0.0-beta2'
compile 'com.squareup.retrofit:adapter-rxjava:2.0.0-beta2'
compile 'com.squareup.retrofit:converter-gson:2.0.0-beta2'
compile 'com.squareup.picasso:picasso:2.5.2'
recyclerview和picasso为了显示. retrofit系列是网络请求.
主页使用一个简单的列表视图, 展示Github的用户信息.
public class NetworkActivity extends Activity {
@Bind(R.id.network_rv_list) RecyclerView mRvL
@Override protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_network);
ButterKnife.bind(this);
LinearLayoutManager layoutManager = new LinearLayoutManager(this);
layoutManager.setOrientation(LinearLayoutManager.VERTICAL);
mRvList.setLayoutManager(layoutManager);
UserListAdapter adapter = new UserListAdapter(this::gotoDetailPage);
NetworkWrapper.getUsersInto(adapter);
mRvList.setAdapter(adapter);
public interface UserClickCallback {
void onItemClicked(String name);
private void gotoDetailPage(String name) {
startActivity(NetworkDetailActivity.from(NetworkActivity.this, name));
在列表中提供点击用户信息跳转至用户详情.
NetworkWrapper.getUsersInto(adapter) 请求网络, 设置适配器信息.
关键部分, 适配器, 其中包含ViewHolder类和数据类.
public class UserListAdapter extends RecyclerView.Adapter&UserListAdapter.UserViewHolder& {
private List&GitHubUser& mU
private NetworkActivity.UserClickCallback mC
public UserListAdapter(NetworkActivity.UserClickCallback callback) {
mUsers = new ArrayList&&();
mCallback =
public void addUser(GitHubUser user) {
mUsers.add(user);
notifyItemInserted(mUsers.size() - 1);
@Override public UserViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
View item = LayoutInflater.from(parent.getContext())
.inflate(R.layout.item_network_user, parent, false);
return new UserViewHolder(item, mCallback);
@Override public void onBindViewHolder(UserViewHolder holder, int position) {
holder.bindTo(mUsers.get(position));
@Override public int getItemCount() {
return mUsers.size();
public static class UserViewHolder extends RecyclerView.ViewHolder {
@Bind(R.id.network_item_iv_user_picture) ImageView mIvUserP
@Bind(R.id.network_item_tv_user_name) TextView mTvUserN
@Bind(R.id.network_item_tv_user_login) TextView mTvUserL
@Bind(R.id.network_item_tv_user_page) TextView mTvUserP
public UserViewHolder(View itemView, NetworkActivity.UserClickCallback callback) {
super(itemView);
ButterKnife.bind(this, itemView);
itemView.setOnClickListener(v -&
callback.onItemClicked(mTvUserLogin.getText().toString()));
public void bindTo(GitHubUser user) {
mTvUserName.setText(user.name);
mTvUserLogin.setText(user.login);
mTvUserPage.setText(user.repos_url);
Picasso.with(mIvUserPicture.getContext())
.load(user.avatar_url)
.placeholder(R.drawable.ic_person_black_24dp)
.into(mIvUserPicture);
public static class GitHubUser {
public String avatar_
public String repos_
添加数据addUser, 其中notifyItemInserted通知更新.
可以自动生成Json解析类的.
首先创建`Retrofit``服务, 通过服务获取数据, 再依次分发给适配器.
public class NetworkWrapper {
private static final String[] mFamousUsers =
{&SpikeKing&, &JakeWharton&, &rock3r&, &Takhion&, &dextorer&, &Mariuxtheone&};
public static void getUsersInto(final UserListAdapter adapter) {
GitHubService gitHubService =
ServiceFactory.createServiceFrom(GitHubService.class, GitHubService.ENDPOINT);
Observable.from(mFamousUsers)
.flatMap(gitHubService::getUserData)
.subscribeOn(Schedulers.newThread())
.observeOn(AndroidSchedulers.mainThread())
.subscribe(adapter::addUser);
public static void getReposInfo(final String username, final RepoListAdapter adapter) {
GitHubService gitHubService =
ServiceFactory.createServiceFrom(GitHubService.class, GitHubService.ENDPOINT);
gitHubService.getRepoData(username)
.flatMap(Observable::from)
.subscribeOn(Schedulers.newThread())
.observeOn(AndroidSchedulers.mainThread())
.subscribe(adapter::addRepo);
网络请求无法在主线程上执行, 需要启动异步线程, 如Schedulers.newThread().
使用工厂模式ServiceFactory创建服务, 也可以单独创建服务.
创建Retrofit服务的工厂类.
public class ServiceFactory {
public static &T& T createServiceFrom(final Class&T& serviceClass, String endpoint) {
Retrofit adapter = new Retrofit.Builder()
.baseUrl(endpoint)
.addCallAdapterFactory(RxJavaCallAdapterFactory.create())
.addConverterFactory(GsonConverterFactory.create())
return adapter.create(serviceClass);
这是Retrofit 2.0的写法, 注意需要添加Rx和Gson的解析.
设置网络请求的Url.
public interface GitHubService {
String ENDPOINT = &&;
@GET(&/users/{user}&)
Observable&UserListAdapter.GitHubUser& getUserData(@Path(&user&) String user);
@GET(&/users/{user}/repos&)
Observable&RepoListAdapter.GitHubRepo[]& getRepoData(@Path(&user&) String user);
详情页面与主页类似, 参考代码, 不做细说.
5. 线程安全
Rx的好处之一就是可以防止内存泄露, 即根据页面生命周期, 处理异步线程的结束. 可以使用库处理生命周期.
Activity类继承RxAppCompatActivity, 替换AppCompatActivity.
启动一个循环线程.
public class SafeActivity extends RxAppCompatActivity {
private static final String TAG = &DEBUG-WCL: & + SafeActivity.class.getSimpleName();
@Bind(R.id.simple_tv_text) TextView mTvT
@Override protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_simple);
ButterKnife.bind(this);
Observable.interval(1, TimeUnit.SECONDS)
.observeOn(AndroidSchedulers.mainThread())
.compose(bindToLifecycle())
.subscribe(this::showTime);
private void showTime(Long time) {
mTvText.setText(String.valueOf(&时间计数: & + time));
Log.d(TAG, &时间计数器: & + time);
protected void onPause() {
super.onPause();
Log.w(TAG, &页面关闭!&);
继承RxAppCompatActivity, 添加bindToLifecycle方法管理生命周期. 当页面onPause时, 会自动结束循环线程. 如果注释这句代码, 则会导致内存泄露.
6. RxBinding
是Rx中处理控件异步调用的方式, 也是由Square公司开发, Jake负责编写. 通过绑定组件, 异步获取事件, 并进行处理. 编码风格非常优雅.
除了RxJava, 再添加RxBinding的依赖.
compile 'com.jakewharton.rxbinding:rxbinding:0.3.0'
compile 'com.jakewharton.rxbinding:rxbinding-appcompat-v7:0.3.0'
compile 'com.jakewharton.rxbinding:rxbinding-design:0.3.0'
Toolbar和Fab, 两个较新的控件.
&?xml version=&1.0& encoding=&utf-8&?&
xmlns:android=&/apk/res/android&
xmlns:tools=&/tools&
android:layout_width=&match_parent&
android:layout_height=&match_parent&
android:fitsSystemWindows=&true&
android:orientation=&vertical&
tools:context=&.BindingActivity&&
android:layout_width=&match_parent&
android:layout_height=&wrap_content&
android:theme=&@style/AppTheme.AppBarOverlay&&
android:id=&@+id/rxbinding_t_toolbar&
android:layout_width=&match_parent&
android:layout_height=&?attr/actionBarSize&
android:background=&?attr/colorPrimary&
android:popupTheme=&@style/AppTheme.PopupOverlay&
tools:targetApi=&21&/&
layout=&@layout/content_rxbinding&/&
android:id=&@+id/rxbinding_fab_fab&
android:layout_width=&wrap_content&
android:layout_height=&wrap_content&
android:layout_gravity=&bottom|end&
android:layout_margin=&@dimen/fab_margin&
android:src=&@android:drawable/ic_dialog_email&/&
两个EditText控件, 对比传统方法和RxBinding方法.
&?xml version=&1.0& encoding=&utf-8&?&
xmlns:android=&/apk/res/android&
xmlns:app=&/apk/res-auto&
xmlns:tools=&/tools&
android:layout_width=&match_parent&
android:layout_height=&match_parent&
android:orientation=&vertical&
android:padding=&@dimen/activity_margin&
app:layout_behavior=&@string/appbar_scrolling_view_behavior&
tools:context=&.BindingActivity&
tools:showIn=&@layout/activity_binding&&
android:layout_width=&match_parent&
android:layout_height=&wrap_content&
android:text=&@string/usual_approach&/&
android:id=&@+id/rxbinding_et_usual_approach&
android:layout_width=&match_parent&
android:layout_height=&48dp&
android:hint=&@null&/&
android:layout_width=&match_parent&
android:layout_height=&wrap_content&
android:text=&@string/reactive_approach&/&
android:id=&@+id/rxbinding_et_reactive_approach&
android:layout_width=&match_parent&
android:layout_height=&48dp&
android:hint=&@null&/&
android:id=&@+id/rxbinding_tv_show&
android:layout_width=&match_parent&
android:layout_height=&wrap_content&/&
使用ButterKnife注入控件, 使用RxBinding方式绑定控件, 异步监听事件.
public class BindingActivity extends AppCompatActivity {
@Bind(R.id.rxbinding_t_toolbar) Toolbar mTT
@Bind(R.id.rxbinding_et_usual_approach) EditText mEtUsualA
@Bind(R.id.rxbinding_et_reactive_approach) EditText mEtReactiveA
@Bind(R.id.rxbinding_tv_show) TextView mTvS
@Bind(R.id.rxbinding_fab_fab) FloatingActionButton mFabF
@Override protected void onCreate(@Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_binding);
ButterKnife.bind(this);
initToolbar();
initFabButton();
initEditText();
private void initToolbar() {
setSupportActionBar(mTToolbar);
ActionBar actionBar = getSupportActionBar();
if (actionBar != null) {
actionBar.setDisplayHomeAsUpEnabled(true);
RxToolbar.itemClicks(mTToolbar).subscribe(this::onToolbarItemClicked);
RxToolbar.navigationClicks(mTToolbar).subscribe(this::onToolbarNavigationClicked);
private void onToolbarItemClicked(MenuItem menuItem) {
String m = &点击\&& + menuItem.getTitle() + &\&&;
Toast.makeText(this, m, Toast.LENGTH_SHORT).show();
private void onToolbarNavigationClicked(Void v) {
Toast.makeText(this, &浏览点击&, Toast.LENGTH_SHORT).show();
@Override public boolean onCreateOptionsMenu(Menu menu) {
getMenuInflater().inflate(R.menu.menu_rxbinding, menu);
return super.onCreateOptionsMenu(menu);
private void initFabButton() {
RxView.clicks(mFabFab).subscribe(this::onFabClicked);
private void onFabClicked(Void v) {
Snackbar snackbar = Snackbar.make(findViewById(android.R.id.content), &点击Snackbar&, Snackbar.LENGTH_SHORT);
snackbar.show();
RxSnackbar.dismisses(snackbar).subscribe(this::onSnackbarDismissed);
private void onSnackbarDismissed(int event) {
String text = &Snackbar消失代码:& +
Toast.makeText(this, text, Toast.LENGTH_SHORT).show();
private void initEditText() {
mEtUsualApproach.addTextChangedListener(new TextWatcher() {
public void beforeTextChanged(CharSequence s, int start, int count, int after) {
@Override public void onTextChanged(CharSequence s, int start, int before, int count) {
mTvShow.setText(s);
@Override public void afterTextChanged(Editable s) {
RxTextView.textChanges(mEtReactiveApproach).subscribe(mTvShow::setText);
Toolbar使用RxToolbar监听点击事件; Snackbar使用RxSnackbar监听;
EditText使用RxTextView监听; 其余使用RxView监听.
OK, That's all! Enjoy It!
文/SpikeKing(简书作者)
原文链接:/p/6d1ef9f43cdc
著作权归作者所有,转载请联系作者获得授权,并标注“简书作者”。
一、不得利用本站危害国家安全、泄露国家秘密,不得侵犯国家社会集体的和公民的合法权益,不得利用本站制作、复制和传播不法有害信息!
二、互相尊重,对自己的言论和行为负责。
本文标题:
本页链接:博客访问: 49898
博文数量: 13
博客积分: 296
博客等级: 二等列兵
技术积分: 105
注册时间:
IT168企业级官微
微信号:IT168qiye
系统架构师大会
微信号:SACC2013
分类: Java
在Android平台上可以使用Simple API for XML(SAX) 、 Document Object Model(DOM)和Android附带的pull解析器解析XML文件。&下面是本例子要解析的XML文件:文件名称:itcast.xml<?xml version="1.0" encoding="UTF-8"?><persons><person id="23"><name>李明</name><age>30</age></person><person id="20"><name>李向梅</name><age>25</age></person></persons>例子定义了一个javabean用于存放上面解析出来的xml内容, 这个javabean为Person,代码:public class Person {& & private Integer id;& & private String name;& & private Short age;& & public Integer getId() {& & & & return id;& & }& & public void setId(Integer id) {& &&&
& this.id = id;& & }&&&&public String getName() {&&&&
&&&return name;&&&&}&&&&public void setName(String name) {&
&&&&&&this.name = name;&&&&}&&&&public Short getAge() {&&& & &&return age;&&&&}&&&&public void setAge(Short age) {&
&&&&&&this.age = age;&&&&}}使用SAX读取XML文件SAX是一个解析速度快并且占用内存少的xml解析器,非常适合用于Android等移动设备。&SAX解析XML文件采用的是事件驱动,也就是说,它并不需要解析完整个文档,在按内容顺序解析文档的过程中,SAX会判断当前读到的字符是否合法XML语法中的某部分,如果符合就会触发事件。所谓事件,其实就是一些回调(callback)方法,这些方法(事件)定义在ContentHandler接口。下面是一些ContentHandler接口常用的方法:startDocument()&&当遇到文档的开头的时候,调用这个方法,可以在其中做一些预处理的工作。endDocument()&&&&和上面的方法相对应,当文档结束的时候,调用这个方法,可以在其中做一些善后的工作。&startElement(String namespaceURI, String localName, String qName, Attributes atts)&&&&当读到一个开始标签的时候,会触发这个方法。namespaceURI就是命名空间,localName是不带命名空间前缀的标签名,qName是带命名空间前缀的标签名。通过atts可以得到所有的属性名和相应的值。要注意的是SAX中一个重要的特点就是它的流式处理,当遇到一个标签的时候,它并不会纪录下以前所碰到的标签,也就是说,在startElement()方法中,所有你所知道的信息,就是标签的名字和属性,至于标签的嵌套结构,上层标签的名字,是否有子元属等等其它与结构相关的信息,都是不得而知的,都需要你的程序来完成。这使得SAX在编程处理上没有DOM来得那么方便。endElement(String uri, String localName, String name)&&&这个方法和上面的方法相对应,在遇到结束标签的时候,调用这个方法。characters(char[] ch, int start, int length)&&&&这个方法用来处理在XML文件中读到的内容,第一个参数用于存放文件的内容,后面两个参数是读到的字符串在这个数组中的起始位置和长度,使用new String(ch,start,length)就可以获取内容。解析itcast.xml触发的事件为:读到的标签及内容&&&&&& 触发事件&{文档开始}&&&&&&&&& startDocument()&&&&&&&&&&& startElement(, "persons", null, "{Attributes}")"\n\t"&&&&&&&&&&&&& characters("...", "12", "2")&&&&&&&&&&& startElement(, "person", null, "{Attributes}")"\n\t\t"&&&&&&&&&&& characters("...", "31", "3")&&&&&&&&&&&&& startElement(, "name", null, "{Attributes}")"李明"&&&&&&&&&&&&& characters("...", "40", "2")&&&&&&&&&&&& endElement("", "name", null)"\n\t\t"&&&&&&&&&&& characters("...", "50", "3")&&&&&&&&&&&&&& startElement(, "age", null, "{Attributes}")"30"&&&&&&&&&&&&&&& characters("...", "58", "2")&&&&&&&&&&&&& endElement("", "age", null)"\n\t"&&&&&&&&&&&&& characters("...", "67", "2")&&&&&&&&&& endElement("", "person", null)"\n\t"&&&&&&&&&&&&& characters("...", "79", "2")&&&&&&&&&&& startElement(, "person", null, "{Attributes}")"\n\t\t"&&&&&&&&&&& characters("...", "98", "3")&&&&&&&&&&&&& startElement(, "name", null, "{Attributes}")"李向梅"&&&&&&&&&&& characters("...", "107", "3")&&&&&&&&&&&& endElement("", "name", null)"\n\t\t"&&&&&&&&&&& characters("...", "118", "3")&&&&&&&&&&&&&& startElement(, "age", null, "{Attributes}")"25"&&&&&&&&&&&&&&& characters("...", "126", "2")&&&&&&&&&&&&& endElement("", "age", null)"\n\t"&&&&&&&&&&&&& characters("...", "135", "2")&&&&&&&&&& endElement("", "person", null)"\n"&&&&&&&&&&&&&&& characters("...", "147", "1")&&&&&&&&& endElement("", "persons", null){文档结束}&&&&&&&&& endDocument()&只要为SAX提供实现ContentHandler接口的类,那么该类就可以得到通知事件(实际上就是SAX调用了该类中的回调方法)。因为ContentHandler是一个接口,在使用的时候可能会有些不方便,因此,SAX还为其制定了一个Helper类:DefaultHandler,它实现了这个接口,但是其所有的方法体都为空,在实现的时候,你只需要继承这个类,然后重载相应的方法即可。使用SAX解析itcast.xml的代码如下:public static List<Person> readXML(InputStream inStream) {&&&try {SAXParserFactory spf = SAXParserFactory.newInstance();SAXParser saxParser = spf.newSAXParser(); //创建解析器//设置解析器的相关特性,http://xml.org/sax/features/namespaces = true 表示开启命名空间特性
saxParser.setProperty("http://xml.org/sax/features/namespaces",true);XMLContentHandler handler = new XMLContentHandler();saxParser.parse(inStream, handler);inStream.close();return handler.getPersons();&&&} catch (Exception e) {e.printStackTrace();&&&}&&return null;}import java.util.ArrayList;import java.util.List;import org.xml.sax.Attributes;import org.xml.sax.SAXException;import org.xml.sax.helpers.DefaultHandler;import cn.itcast.xml.domain.Person;public class XMLContentHandler extends DefaultHandler {private List<Person> persons = null;private Person currentPerson;private String tagName = null;//当前解析的元素标签public List<Person> getPersons() {return persons;}/** 接收文档的开始的通知。*/@Override public void startDocument() throws SAXException {persons = new ArrayList<Person>();}/** 接收字符数据的通知。*/@Override public void characters(char[] ch, int start, int length) throws SAXException {if(tagName!=null){String data = new String(ch, start, length);if(tagName.equals("name")){this.currentPerson.setName(data);}else if(tagName.equals("age")){this.currentPerson.setAge(Short.parseShort(data));}}}/** 接收元素开始的通知。* 参数意义如下:*
namespaceURI:元素的命名空间*
localName :元素的本地名称(不带前缀)*
qName :元素的限定名(带前缀)*
atts :元素的属性集合*/@Override public void startElement(String namespaceURI, String localName, String qName, Attributes atts) throws SAXException {if(localName.equals("person")){currentPerson = new Person();currentPerson.setId(Integer.parseInt(atts.getValue("id")));}this.tagName = localName;}/** 接收文档的结尾的通知。* 参数意义如下:*
uri :元素的命名空间*
localName :元素的本地名称(不带前缀)*
name :元素的限定名(带前缀)* */@Override public void endElement(String uri, String localName, String name) throws SAXException {if(localName.equals("person")){persons.add(currentPerson);currentPerson = null;}this.tagName = null;}}使用DOM读取XML文件除了可以使用 SAX解析XML文件,大家也可以使用熟悉的DOM来解析XML文件。 DOM解析XML文件时,会将XML文件的所有内容读取到内存中,然后允许您使用DOM API遍历XML树、检索所需的数据。使用DOM操作XML的代码看起来比较直观,并且,在某些方面比基于SAX的实现更加简单。但是,因为DOM需要将XML文件的所有内容读取到内存中,所以内存的消耗比较大,特别对于运行Android的移动设备来说,因为设备的资源比较宝贵,所以建议还是采用SAX来解析XML文件,当然,如果XML文件的内容比较小采用DOM是可行的。import java.io.InputStream;import java.util.ArrayList;import java.util.List;import javax.xml.parsers.DocumentBuilder;import javax.xml.parsers.DocumentBuilderFactory;import org.w3c.dom.Document;import org.w3c.dom.Element;import org.w3c.dom.Node;import org.w3c.dom.NodeList;import cn.itcast.xml.domain.Person;/*** 使用Dom解析xml文件**/public class DomXMLReader {public static List<Person> readXML(InputStream inStream) {List<Person> persons = new ArrayList<Person>();DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();try {DocumentBuilder builder = factory.newDocumentBuilder();Document dom = builder.parse(inStream);Element root = dom.getDocumentElement();NodeList items = root.getElementsByTagName("person");//查找所有person节点for (int i = 0; i < items.getLength(); i++) {Person person = new Person();//得到第一个person节点Element personNode = (Element) items.item(i);//获取person节点的id属性值person.setId(new Integer(personNode.getAttribute("id")));//获取person节点下的所有子节点(标签之间的空白节点和name/age元素)NodeList childsNodes = personNode.getChildNodes();for (int j = 0; j < childsNodes.getLength(); j++) {Node node = (Node) childsNodes.item(j); //判断是否为元素类型if(node.getNodeType() == Node.ELEMENT_NODE){
Element childNode = (Element) node;&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&//判断是否name元素&&&if ("name".equals(childNode.getNodeName())) {&&&&//获取name元素下Text节点,然后从Text节点获取数据&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&person.setName(childNode.getFirstChild().getNodeValue());
&&&} else if (“age”.equals(childNode.getNodeName())) {&&&&&&&&&&&&&person.setAge(new Short(childNode.getFirstChild().getNodeValue()));&&&}}&&&&&&&}&&&persons.add(person);}inStream.close();} catch (Exception e) {e.printStackTrace();}return persons;}使用Pull解析器读取XML文件除了可以使用 SAX和DOM解析XML文件,大家也可以使用Android内置的Pull解析器解析XML文件。 Pull解析器的运行方式与 SAX 解析器相似。它提供了类似的事件,如:开始元素和结束元素事件,使用parser.next()可以进入下一个元素并触发相应事件。事件将作为数值代码被发送,因此可以使用一个switch对感兴趣的事件进行处理。当元素开始解析时,调用parser.nextText()方法可以获取下一个Text类型元素的值。Pull解析器的源码及文档下载网址:http://www.xmlpull.org/import org.xmlpull.v1.XmlPullParser;import android.util.Xml;import cn.itcast.xml.domain.Person;public class PullXMLReader {public static List<Person> readXML(InputStream inStream) {XmlPullParser parser = Xml.newPullParser();try {parser.setInput(inStream, "UTF-8");int eventType = parser.getEventType();Person currentPerson = null;List<Person> persons = null;while (eventType != XmlPullParser.END_DOCUMENT) {switch (eventType) {case XmlPullParser.START_DOCUMENT://文档开始事件,可以进行数据初始化处理persons = new ArrayList<Person>();break;case XmlPullParser.START_TAG://开始元素事件String name = parser.getName();if (name.equalsIgnoreCase("person")) {currentPerson = new Person();currentPerson.setId(new Integer(parser.getAttributeValue(null, "id")));} else if (currentPerson != null) {if (name.equalsIgnoreCase("name")) {currentPerson.setName(parser.nextText());// 如果后面是Text元素,即返回它的值} else if (name.equalsIgnoreCase("age")) {currentPerson.setAge(new Short(parser.nextText()));}}break;case XmlPullParser.END_TAG://结束元素事件if (parser.getName().equalsIgnoreCase("person") && currentPerson != null) {persons.add(currentPerson);currentPerson = null;}break;}eventType = parser.next();}inStream.close();return persons;} catch (Exception e) {e.printStackTrace();}return null;}}使用Pull解析器生成XML文件有些时候,我们需要生成一个XML文件,生成XML文件的方法有很多,如:可以只使用一个StringBuilder组拼XML内容,然后把内容写入到文件中;或者使用DOM API生成XML文件,或者也可以使用pull解析器生成XML文件,这里推荐大家使用Pull解析器。使用Pull解析器生成一个与itcast.xml文件内容相同的myitcast.xml文件。public static String writeXML(List<Person> persons, Writer writer){&&&&XmlSerializer serializer = Xml.newSerializer();&&&&try {&&&&&&&&serializer.setOutput(writer);&&&&&&&&serializer.startDocument("UTF-8", true);&&&&&&//第一个参数为命名空间,如果不使用命名空间,可以设置为null&&&&&&&&serializer.startTag("", "persons");&&&&&&&&for (Person person : persons){&&&&&&&&&&&&serializer.startTag("", "person");&&&&&&&&&&&&serializer.attribute("", "id", person.getId().toString());&&&&&&&&&&&&serializer.startTag("", "name");&&&&&&&&&&&&serializer.text(person.getName());&&&&&&&&&&&&serializer.endTag("", "name");&&&&&&&&&&&&serializer.startTag("", "age");&&&&&&&&&&&&serializer.text(person.getAge().toString());&&&&&&&&&&&&serializer.endTag("", "age");&&&&&&&&&&&&serializer.endTag("", "person");&&&&&&&&}&&&&&&&&serializer.endTag("", "persons");&&&&&&&&serializer.endDocument();&&&&&&&&return writer.toString();&&&&} catch (Exception e) {&&&&&&&&e.printStackTrace();&&&&}&&&&return null;}使用代码如下(生成XML文件):File xmlFile = new File("myitcast.xml");FileOutputStream outStream = new FileOutputStream(xmlFile);OutputStreamWriter outStreamWriter = new OutputStreamWriter(outStream, "UTF-8");BufferedWriter writer = new BufferedWriter(outStreamWriter);writeXML(persons, writer);writer.flush();writer.close();如果只想得到生成的xml内容,可以使用StringWriter:StringWriter writer = new StringWriter();writeXML(persons, writer);String content = writer.toString();&
阅读(1418) | 评论(3) | 转发(0) |
相关热门文章
给主人留下些什么吧!~~
好东西啊,谢谢分享了
很好的例子啊,简单易懂,顶一个
android用dom解析xml效率怎么样&&???
请登录后评论。

我要回帖

更多关于 android 解析xml文件 的文章

 

随机推荐