Статьи

Android SDK: создание приложения для сканирования книг — интерфейс и поиск книг

С помощью библиотеки ZXing вы можете создавать приложения для Android с функцией сканирования штрих-кода. В Android SDK: создание считывателя штрих-кода мы реализовали базовое считывание штрих-кода с помощью библиотеки в простом приложении. В этой серии руководств мы будем опираться на то, что мы узнали, чтобы создать приложение, которое будет сканировать книги и извлекать связанную с ними информацию из API Google Книг.

Эта серия статей о создании приложения для сканирования книг состоит из трех частей:

В этой части серии мы создадим оставшуюся часть пользовательского интерфейса для приложения и выполним поиск книг, используя данные сканирования пользователей. Это потребует использования внутреннего класса AsyncTask для извлечения данных через Интернет из основного потока пользовательского интерфейса приложения.

Вот предварительный просмотр приложения, над которым мы работаем:

Приложение Book Scanner

Приложение позволит пользователям сканировать штрих-коды книг, а затем искать отсканированные книги в Google Книгах, представляя результаты в интерфейсе приложения. В заключительной части серии мы обработаем возвращенные результаты поиска книг JSON. Мы будем использовать WebView для представления предварительного просмотра книги, если она есть, и будем ссылаться на страницу книги на сайте Google.


В прошлый раз мы создали базовую схему пользовательского интерфейса и кнопку сканирования — давайте завершим оставшиеся элементы. Как вы можете видеть из изображения для предварительного просмотра выше, пользовательский интерфейс будет отображать выборку информации из поиска в Google Книгах, включая название книги, автора, миниатюру изображения, дату публикации, описание, звездный рейтинг и количество оценок. Для звездного рейтинга мы будем отображать звездное изображение несколько раз, чтобы соответствовать рейтингу для книги. Мы также отобразим кнопку со ссылкой на предварительный просмотр книги, если она есть, и другую кнопку со ссылкой на страницу книги в Google Книгах.

Откройте ваш основной файл макета. После того, как кнопка сканирования мы добавили в прошлый раз, внутри Относительного макета добавьте линейный макет для информации о книге:

1
2
3
4
5
6
<LinearLayout
    android:layout_width=»match_parent»
    android:layout_height=»match_parent»
    android:orientation=»vertical»
    android:layout_below=»@id/scan_button»>
</LinearLayout>

Внутри этого линейного макета сначала добавьте текстовое представление для названия книги:

1
2
3
4
5
6
7
<TextView
    android:id=»@+id/book_title»
    android:layout_width=»wrap_content»
    android:layout_height=»wrap_content»
    android:textColor=»#ff000000″
    android:textIsSelectable=»true»
    android:textStyle=»bold» />

Каждый элемент пользовательского интерфейса, в котором мы отображаем извлеченную информацию, имеет идентификатор, чтобы мы могли ссылаться на него в коде Java-деятельности. Вы можете, конечно, изменить цвета и стилистику, если хотите. Затем, все еще внутри линейного макета, добавьте текстовое представление для автора:

1
2
3
4
5
6
<TextView
    android:id=»@+id/book_author»
    android:layout_width=»wrap_content»
    android:layout_height=»wrap_content»
    android:textColor=»#ffa13143″
    android:textIsSelectable=»true» />

Затем добавьте просмотр изображения для миниатюрного изображения:

1
2
3
4
5
<ImageView
    android:id=»@+id/thumb»
    android:layout_width=»50dp»
    android:layout_height=»80dp»
    android:contentDescription=»@string/thumb» />

Изображение, которое мы собираемся получить, имеет ширину приблизительно 80 пикселей в соответствии с документацией API Google Книг , поэтому мы немного округляем его — на самом деле изображения имеют разный размер, поэтому это позволяет избежать чрезмерного растягивания любого из них и получения в худшем качестве. Добавьте указанную строку в ваш XML-файл «res / values ​​/ strings»:

1
<string name=»thumb»>Book thumbnail</string>

Вернитесь в файл макета, после просмотра изображений добавьте еще один текстовый просмотр для даты публикации:

1
2
3
4
5
6
<TextView
    android:id=»@+id/book_date»
    android:layout_width=»wrap_content»
    android:layout_height=»wrap_content»
    android:textColor=»#ff592d94″
    android:textIsSelectable=»true» />

Затем добавьте текстовое представление для описания:

1
2
3
4
5
6
<TextView
    android:id=»@+id/book_description»
    android:layout_width=»wrap_content»
    android:layout_height=»wrap_content»
    android:textColor=»#ff000000″
    android:textIsSelectable=»true» />

Теперь мы хотим добавить еще один линейный макет внутри существующего. В этом макете мы будем динамически формировать отображение звездного рейтинга при получении информации о книге. После описания текста Просмотр:

1
2
3
4
5
6
<LinearLayout
    android:id=»@+id/star_layout»
    android:layout_width=»wrap_content»
    android:layout_height=»wrap_content»
    android:orientation=»horizontal» >
</LinearLayout>

На этот раз макет горизонтальный, поэтому звезды будут отображаться на горизонтальной линии. Оставьте этот Linear Layout пустым, так как мы будем заполнять его при запуске приложения. После этого, но все еще внутри первого линейного макета, который мы добавили, добавьте текстовое представление для количества оценок:

1
2
3
4
5
6
7
<TextView
    android:id=»@+id/book_rating_count»
    android:layout_width=»wrap_content»
    android:layout_height=»wrap_content»
    android:textColor=»#ff2d6994″
    android:textIsSelectable=»true»
    android:textStyle=»italic» />

Наконец, нам нужен еще один линейный макет внутри первого, который будет содержать кнопки предварительного просмотра и веб-ссылки. После подсчета рейтинга Просмотр текста:

1
2
3
4
5
<LinearLayout
    android:layout_width=»wrap_content»
    android:layout_height=»wrap_content»
    android:orientation=»horizontal» >
</LinearLayout>

Внутри этого, добавьте две кнопки для предварительного просмотра книги и ссылку на Google Книги:

01
02
03
04
05
06
07
08
09
10
11
<Button
    android:id=»@+id/preview_btn»
    android:layout_width=»wrap_content»
    android:layout_height=»wrap_content»
    android:text=»@string/pre» />
 
<Button
    android:id=»@+id/link_btn»
    android:layout_width=»wrap_content»
    android:layout_height=»wrap_content»
    android:text=»@string/link» />

Завершите макет, добавив эти две указанные строки в ваш XML-файл «res / values ​​/ strings»:

1
2
<string name=»pre»>Preview</string>
<string name=»link»>Web</string>

Теперь давайте подготовим приложение к ссылкам на эти элементы пользовательского интерфейса. В свой основной класс Activity добавьте следующие операторы импорта:

01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
import java.io.BufferedReader;
import java.io.InputStream;
import java.io.InputStreamReader;
 
import org.apache.http.HttpEntity;
import org.apache.http.HttpResponse;
import org.apache.http.StatusLine;
import org.apache.http.client.HttpClient;
import org.apache.http.client.methods.HttpGet;
import org.apache.http.impl.client.DefaultHttpClient;
 
import android.os.AsyncTask;
import android.widget.ImageView;
import android.widget.LinearLayout;
import android.widget.TextView;

У вас уже должна быть единственная переменная экземпляра для кнопки сканирования. Расширьте строку, в которой вы объявили, чтобы включить две другие кнопки, которые мы только что добавили:

1
private Button scanBtn, previewBtn, linkBtn;

После этой строки добавьте объявления для текстовых представлений:

1
private TextView authorText, titleText, descriptionText, dateText, ratingCountText;

Затем добавьте линейный макет для раздела звездного рейтинга:

1
private LinearLayout starLayout;

Добавить эскиз изображения:

1
private ImageView thumbView;

В разделе «Звездный рейтинг» мы будем отображать одну звездочку за каждую книгу, присуждаемую авторами данных Google Книг. Мы будем использовать следующее изображение, которое вы можете найти в исходном коде для скачивания или скачать прямо здесь:

звезда

Поместите это изображение в папку (и) вашего приложения или создайте альтернативное изображение по вашему выбору. В вашем классе Activity добавьте переменную экземпляра массива для звездных изображений:

1
private ImageView[] starViews;

Внутри метода onCreate теперь мы можем получить ссылки на эти элементы. У вас уже должен быть код, создающий экземпляр переменной кнопки сканирования и устанавливающий прослушиватель щелчков для нее. После этого кода сделайте то же самое для кнопок предварительного просмотра и ссылки, установив их изначально невидимыми, чтобы они отображались только после того, как пользователь отсканировал книгу:

1
2
3
4
5
6
previewBtn = (Button)findViewById(R.id.preview_btn);
previewBtn.setVisibility(View.GONE);
previewBtn.setOnClickListener(this);
linkBtn = (Button)findViewById(R.id.link_btn);
linkBtn.setVisibility(View.GONE);
linkBtn.setOnClickListener(this);

Далее создайте экземпляры оставшихся элементов пользовательского интерфейса, используя значения идентификаторов, которые мы дали им в макете:

1
2
3
4
5
6
7
authorText = (TextView)findViewById(R.id.book_author);
titleText = (TextView)findViewById(R.id.book_title);
descriptionText = (TextView)findViewById(R.id.book_description);
dateText = (TextView)findViewById(R.id.book_date);
starLayout = (LinearLayout)findViewById(R.id.star_layout);
ratingCountText = (TextView)findViewById(R.id.book_rating_count);
thumbView = (ImageView)findViewById(R.id.thumb);

Теперь создайте экземпляр массива для звезды.

1
2
3
4
starViews=new ImageView[5];
for(int s=0; s<starViews.length; s++){
    starViews[s]=new ImageView(this);
}

Мы установим изображение звезды в правильном количестве просмотров изображений для оценки каждой отсканированной книги.


В прошлый раз мы получили ключ API для Google Книг, поэтому давайте использовать его для поиска книг. В вашем методе onActivityResult вы провели сканирование и получили результаты. Сканер ZXing способен сканировать различные типы штрих-кодов, но, поскольку это приложение для сканирования книг, нас интересуют только штрих-коды EAN. После строк, в которых вы создаете экземпляры переменных scanContent и scanFormat , но все еще внутри оператора if , выполните проверку результата сканирования, прежде чем продолжить:

1
2
3
4
5
6
7
8
if(scanContent!=null && scanFormat!=null && scanFormat.equalsIgnoreCase(«EAN_13»)){
//book search
}
else{
    Toast toast = Toast.makeText(getApplicationContext(),
        «Not a valid scan!», Toast.LENGTH_SHORT);
        toast.show();
}

Если отсканированный штрих-код не является EAN, мы просто выводим сообщение об ошибке. Теперь мы можем подготовить строку поиска в Google Книгах. Вы можете искать API различными способами — мы будем искать по ISBN, так как у нас есть эти отсканированные данные. Поисковый URL ISBN имеет следующую структуру:

1
https://www.googleapis.com/books/v1/volumes?q=isbn:0000000000000&key=your_key

Внутри нового блока if создайте эту строку, используя данные сканирования и ключ API:

1
2
String bookSearchString = «https://www.googleapis.com/books/v1/volumes?»+
    «q=isbn:»+scanContent+»&key=your_key»;

Мы включаем содержимое сканирования, которое должно быть номером EAN. Добавьте свой собственный ключ API.

Мы будем использовать класс AsyncTask для запроса и получения результатов поиска книг. Внутри вашего класса Activity после метода onActivityResult добавьте объявление класса:

1
2
3
private class GetBookInfo extends AsyncTask<String, Void, String> {
//fetch book info
}

Метод класса doInBackground будет получать строку URL и возвращать строку, представляющую результаты поиска. Внутри класса добавьте метод:

1
2
3
4
@Override
protected String doInBackground(String… bookURLs) {
//request book info
}

Это гарантирует, что выборка данных не будет происходить в основном потоке пользовательского интерфейса приложения. Внутри doInBackground создайте String Builder для хранения результатов:

1
StringBuilder bookBuilder = new StringBuilder();

Хотя мы знаем, что будет только одна строка URL-адреса поиска, метод предполагает получение нескольких параметров, поэтому добавьте цикл:

1
2
3
for (String bookSearchURL : bookURLs) {
//search urls
}

Внутри цикла создайте HTTP-клиент для запроса данных:

1
HttpClient bookClient = new DefaultHttpClient();

Как всегда с операциями ввода / вывода, существует вероятность ошибок, поэтому добавьте блоки try и catch следующим образом:

1
2
3
4
try {
    //get the data
}
catch(Exception e){ e.printStackTrace();

Внутри блока try создайте объект HTTP Get, передав ему строку поиска URL:

1
HttpGet bookGet = new HttpGet(bookSearchURL);

Выполнить запрос:

1
HttpResponse bookResponse = bookClient.execute(bookGet);

Проверьте статус ответа:

1
2
3
4
StatusLine bookSearchStatus = bookResponse.getStatusLine();
if (bookSearchStatus.getStatusCode()==200) {
    //we have a result
}

Внутри блока if получите сущность сообщения из ответа:

1
HttpEntity bookEntity = bookResponse.getEntity();

Теперь прочитайте содержимое в Buffered Reader, чтобы мы могли обработать его:

1
2
3
InputStream bookContent = bookEntity.getContent();
InputStreamReader bookInput = new InputStreamReader(bookContent);
BufferedReader bookReader = new BufferedReader(bookInput);

Проработайте содержимое ответа, добавив его в String Builder по одной строке:

1
2
3
4
String lineIn;
while ((lineIn=bookReader.readLine())!=null) {
    bookBuilder.append(lineIn);
}

Теперь мы можем вернуть этот результат. После закрывающей скобки цикла for, но все еще внутри doInBackground :

1
return bookBuilder.toString();

Эта возвращаемая строка будет получена методом onPostExecute , который мы реализуем в следующий раз. В нем мы обработаем возвращенную информацию о книге и отобразим ее в пользовательском интерфейсе. Мы также создадим экземпляр этого класса AsyncTask и передадим ему строку поиска URL.


В этом уроке мы завершили пользовательский интерфейс, подготовили строку поиска URL и начали реализовывать класс AsyncTask для извлечения данных книги в фоновом режиме. В тот момент, когда вы запускаете ваше приложение, оно не будет извлекать какие-либо данные — мы реализуем оставшуюся функциональность в следующий раз, в последней части серии. Мы также создадим второй AsyncTask для извлечения эскиза книги, добавим в приложение второе действие для предварительного просмотра книги и позаботимся о сохранении состояния приложения.