使用Zxing及豆瓣API | 疯狂的键盘

使用Zxing及豆瓣API

最近在做团队图书管理的一个Android端。因为需要通过手机扫描来输入图书信息(人工一条一条地输入,作为技术人员太受不了了),需要使用ZXing的API扫描图书ISBN,及使用豆瓣API来获取图书信息。

由于时间关系,这里没有使用ZXing的jar包,而是下载并安装了它的开源项目——条码扫描器,然后调用里面的Activity扫描再获取结果。
首先到市场下载Barcode Scaner(或搜索条码扫描器),下载安装。
下面先贴上Activity的布局代码,因为是demo版,而且在内部使用,就没去好好做布局设计,只是把需要的控件都写上。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
<?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上获得最新代码。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
/*
 * @(#)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
 *
 *
 * 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 (66704238@51uc.com)
 */
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的过程比较简单,

1
2
Intent intent = new Intent("com.google.zxing.client.android.SCAN");
this.startActivityForResult(intent, HOME_ACTIVITY);

然后再在onActivityResult方法中对返回的结果进行处理就好了。
然后从豆瓣API中获得的是xml格式的内容,这里我就使用了android自带的pull解析器。我需要获得的图书信息相对较少,Book的JavaBean如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
/*
 * @(#)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
 *
 *
 * 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 (66704238@51uc.com)
 */
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 + "]";
    }
}

然后解析器的代码如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
/*
 * @(#)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
 *
 *
 * 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 (66704238@51uc.com)
 */
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资源,如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
<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>

最后的结果是这样子的:使用Zxing及豆瓣API

相关文章: