本文原创,转载请注明原文地址:http://maosidiaoxian.iteye.com/blog/1743296或我在sinaapp上的博客:http://msdxblog.sinaapp.com/?p=716。
最近在做团队图书管理的一个Android端。因为需要通过手机扫描来输入图书信息(人工一条一条地输入,作为技术人员太受不了了),需要使用ZXing的API扫描图书ISBN,及使用豆瓣API来获取图书信息。
由于时间关系,这里没有使用ZXing的jar包,而是下载并安装了它的开源项目——条码扫描器,然后调用里面的Activity扫描再获取结果。
首先到市场下载Barcode Scaner(或搜索条码扫描器),下载安装。
下面先贴上Activity的布局代码,因为是demo版,而且在内部使用,就没去好好做布局设计,只是把需要的控件都写上。
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical" >
<Button
android:id="@+id/home_scan"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="@string/button_scan" />
<TextView
android:id="@+id/home_result_scan"
android:layout_width="wrap_content"
android:layout_height="wrap_content" />
<TextView
android:id="@+id/home_book_info"
android:layout_width="wrap_content"
android:layout_height="wrap_content" />
<Button
android:id="@+id/home_upload_result"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="@string/button_upload" />
<TextView
android:id="@+id/home_result_upload"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:singleLine="false" />
<LinearLayout
android:layout_width="fill_parent"
android:layout_height="wrap_content" >
<Button
android:id="@+id/home_borrow_book"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="@string/borrow_book" />
<Spinner
android:id="@+id/home_users"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="right" />
</LinearLayout>
<Button
android:id="@+id/home_return_book"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="@string/return_book" />
<Button
android:id="@+id/home_user_manager"
android:layout_width="wrap_content"
android:text="@string/manager_user"
android:layout_height="wrap_content" />
</LinearLayout>
然后在我们的项目中,写一个Activity来调用Zxing的扫描功能,并通过它返回的结果访问互联网获取信息。
下面是该Activity的代码。这里对于控件及事件的绑定,我使用了自己封装的一个工具(Androidkit)来简化这些代码,所以你们会看到许多类似@AndroidView的注解,这个工具可以在http://code.google.com/p/cfuture-androidkit/获取,或从https://github.com/msdx/androidkit上获得最新代码。
/*
* @(#)HomeActivity.java Project:bookscan
* Date:2012-12-3
*
* Copyright (c) 2011 CFuture09, Institute of Software,
* Guangdong Ocean University, Zhanjiang, GuangDong, China.
* All rights reserved.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.sinaapp.msdxblog.bookscan.activity;
import org.apache.http.HttpResponse;
import org.apache.http.client.methods.HttpGet;
import org.apache.http.impl.client.DefaultHttpClient;
import android.app.Activity;
import android.content.Intent;
import android.database.Cursor;
import android.os.Bundle;
import android.os.Handler;
import android.view.View;
import android.widget.SimpleCursorAdapter;
import android.widget.Spinner;
import android.widget.TextView;
import com.sinaapp.msdxblog.androidkit.thread.HandlerFactory;
import com.sinaapp.msdxblog.androidkit.ui.ResBindUtil;
import com.sinaapp.msdxblog.androidkit.ui.UIBindUtil;
import com.sinaapp.msdxblog.androidkit.ui.annotation.AndroidRes;
import com.sinaapp.msdxblog.androidkit.ui.annotation.AndroidRes.ResType;
import com.sinaapp.msdxblog.androidkit.ui.annotation.AndroidView;
import com.sinaapp.msdxblog.androidkit.ui.annotation.OnClick;
import com.sinaapp.msdxblog.bookscan.R;
import com.sinaapp.msdxblog.bookscan.bean.Book;
import com.sinaapp.msdxblog.bookscan.util.DB;
import com.sinaapp.msdxblog.bookscan.util.XMLSax;
/**
* @author Geek_Soledad ([email protected])
*/
public class HomeActivity extends Activity {
private static final int HOME_ACTIVITY = 1990;
private static final String DOUBAN_API = "http://api.douban.com/book/subject/isbn/";
@AndroidView(id = R.id.home_result_scan)
private TextView mTextScan;
@AndroidView(id = R.id.home_book_info)
private TextView mTextBook;
@AndroidView(id = R.id.home_result_upload)
private TextView mTextUpload;
@AndroidView(id = R.id.home_users)
private Spinner mSpinnerUser;
@AndroidRes(id = R.string.result_scan, type = ResType.STRING)
private String mStringScan;
@AndroidRes(id = R.string.result_getting, type = ResType.STRING)
private String mStringGetting;
@AndroidRes(id = R.string.book_info, type = ResType.STRING)
private String mStringBookInfo;
private Handler mGettingBook;
private Book book;
private DB mDb;
private SimpleCursorAdapter mAdapter;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
UIBindUtil.bind(this, R.layout.activity_home);
ResBindUtil.bindAllRes(this);
init();
}
/**
* 初始化参数。
*/
private final void init() {
mGettingBook = HandlerFactory.getNewHandlerInOtherThread("book");
mDb = new DB(this);
Cursor users = mDb.getAllUser();
startManagingCursor(users);
mAdapter = new SimpleCursorAdapter(this,
android.R.layout.simple_spinner_item, users,
new String[] { "username" }, new int[] { android.R.id.text1 });
mAdapter
.setDropDownViewResource(android.R.layout.simple_spinner_dropdown_item);
mSpinnerUser.setAdapter(mAdapter);
}
@OnClick(viewId = { R.id.home_scan, R.id.home_upload_result,
R.id.home_borrow_book, R.id.home_return_book,
R.id.home_user_manager })
public void onButtonClick(View v) {
switch (v.getId()) {
case R.id.home_scan:
Intent intent = new Intent("com.google.zxing.client.android.SCAN");
this.startActivityForResult(intent, HOME_ACTIVITY);
break;
case R.id.home_upload_result:
break;
case R.id.home_borrow_book:
break;
case R.id.home_return_book:
break;
case R.id.home_user_manager:
startActivity(new Intent(this, UserManagerActivity.class));
break;
default:
break;
}
}
@Override
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
if (requestCode != HOME_ACTIVITY) {
super.onActivityResult(requestCode, resultCode, data);
return;
}
if (data == null) {
return;
}
final String isbn = data.getStringExtra("SCAN_RESULT");
mTextScan.setText(String.format(mStringScan, isbn));
if (isbn != null) {
mTextBook.setText(mStringGetting);
mGettingBook.post(new Runnable() {
@Override
public void run() {
DefaultHttpClient client = new DefaultHttpClient();
HttpGet request = new HttpGet(DOUBAN_API + isbn);
try {
HttpResponse response = client.execute(request);
book = XMLSax.sax(response.getEntity().getContent());
String summary = book.getSummary();
summary = summary.substring(0,
summary.length() < 60 ? summary.length() : 60)
.concat("...");
String string = String.format(mStringBookInfo,
book.getName(), book.getAuthor(),
book.getPublisher(), book.getIsbn13(), summary);
updateBookInfoView(string);
} catch (Exception e) {
e.printStackTrace();
}
}
});
}
}
/**
* 更新图书信息
*
* @param string
*/
private void updateBookInfoView(final String string) {
runOnUiThread(new Runnable() {
@Override
public void run() {
mTextBook.setText(string);
}
});
}
@Override
protected void onResume() {
super.onResume();
mAdapter.notifyDataSetChanged();
}
@Override
protected void onDestroy() {
super.onDestroy();
mDb.close();
}
}
里面的功能及流程大致如下:
调用Zxinig的扫描条码的Activity,然后返回该扫描结果,显示扫描结果,然后调用豆瓣的API获取图书信息。接下来是要从我们的服务器上获得该图书的信息(如是否登记,有没有人借走等),但因为服务端还没搭建好,这一部分功能就没去实现。
上面代码中,调用Zxing的过程比较简单,
Intent intent = new Intent("com.google.zxing.client.android.SCAN");
this.startActivityForResult(intent, HOME_ACTIVITY);
然后再在onActivityResult方法中对返回的结果进行处理就好了。
然后从豆瓣API中获得的是xml格式的内容,这里我就使用了android自带的pull解析器。我需要获得的图书信息相对较少,Book的JavaBean如下:
/*
* @(#)BookInfo.java Project:bookscan
* Date:2012-12-3
*
* Copyright (c) 2011 CFuture09, Institute of Software,
* Guangdong Ocean University, Zhanjiang, GuangDong, China.
* All rights reserved.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.sinaapp.msdxblog.bookscan.bean;
/**
* @author Geek_Soledad ([email protected])
*/
public class Book {
private String isbn10;// 10位的ISBN
private String isbn13;// 13位的ISBN
private String name; // 书名
private String author;// 作者名
private String summary;// 简介
private String publisher; // 出版社
private String image; // 封面图片地址
public String getIsbn10() {
return isbn10;
}
public void setIsbn10(String isbn10) {
this.isbn10 = isbn10;
}
public String getIsbn13() {
return isbn13;
}
public void setIsbn13(String isbn13) {
this.isbn13 = isbn13;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getAuthor() {
return author;
}
public void setAuthor(String author) {
this.author = author;
}
public String getSummary() {
return summary;
}
public void setSummary(String summary) {
this.summary = summary;
}
public String getPublisher() {
return publisher;
}
public void setPublisher(String publisher) {
this.publisher = publisher;
}
public String getImage() {
return image;
}
public void setImage(String image) {
this.image = image;
}
@Override
public String toString() {
return "Book [isbn10=" + isbn10 + ", isbn13=" + isbn13 + ", name="
+ name + ", author=" + author + ", summary=" + summary
+ ", publisher=" + publisher + ", image=" + image + "]";
}
}
然后解析器的代码如下:
/*
* @(#)XMLSax.java Project:bookscan
* Date:2012-12-3
*
* Copyright (c) 2011 CFuture09, Institute of Software,
* Guangdong Ocean University, Zhanjiang, GuangDong, China.
* All rights reserved.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.sinaapp.msdxblog.bookscan.util;
import java.io.IOException;
import java.io.InputStream;
import org.xmlpull.v1.XmlPullParser;
import org.xmlpull.v1.XmlPullParserException;
import com.sinaapp.msdxblog.bookscan.bean.Book;
import android.util.Log;
import android.util.Xml;
/**
* @author Geek_Soledad ([email protected])
*/
public class XMLSax {
public static Book sax(InputStream is) {
Book book = null;
XmlPullParser parser = Xml.newPullParser();
try {
parser.setInput(is, "UTF-8");
int eventType = parser.getEventType();
while (eventType != XmlPullParser.END_DOCUMENT) {
switch (eventType) {
case XmlPullParser.START_TAG:
Log.d("test", parser.getName());
if (parser.getName().equals("entry")) {
book = new Book();
} else if (parser.getName().equals("link")) {
if (parser.getAttributeValue(null, "rel").equals("image")) {
book.setImage(parser.getAttributeValue(null, "href"));
}
eventType = parser.next();
}
else if (parser.getName().equals("attribute")) {
String attribute = parser.getAttributeValue(0);
eventType = parser.next();
if (attribute.equals("title")) {
book.setName(parser.getText());
} else if (attribute.equals("author")) {
book.setAuthor(parser.getText());
} else if (attribute.equals("isbn10")) {
book.setIsbn10(parser.getText());
} else if (attribute.equals("isbn13")) {
book.setIsbn13(parser.getText());
} else if ( attribute.equals("publisher")) {
book.setPublisher(parser.getText());
}
} else if (parser.getName().equals("summary")) {
eventType = parser.next();
book.setSummary(parser.getText());
} else if (parser.getName().equals("title")) {
if (book.getName() == null) {
eventType = parser.next();
book.setName(parser.getText());
}
}
break;
case XmlPullParser.END_TAG:
break;
}
eventType = parser.next();
}
} catch (XmlPullParserException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
return book;
}
}
然后是引用到的String资源,如下:
<resources>
<string name="app_name">图书扫描</string>
<string name="bookmark_picker_name">Bookmarks</string>
<string name="button_scan">图书扫描</string>
<string name="button_upload">上传结果</string>
<string name="result_scan">扫描结果为:%s</string>
<string name="result_getting">正在向豆瓣请求数据</string>
<string name="book_info">图书信息:\n\t书名:%1$s\n\t作者:%2$s\n\t出版社:%3$s\n\tISBN:%4$s\n\t简介:%5$s </string>
<string name="borrow_book">借书</string>
<string name="return_book">还书</string>
<string name="manager_user">管理用户</string>
<string name="add">添加</string>
<string name="delete">删除</string>
</resources>
最后的结果是这样子的: