Hi I'm new to Android and using web APIs. I'm currently writing an application that can scan a barcode from a book and then search Google Books for it.
So far I implemented Scandit into my application and I registered and got the API key from Google API console for Books API. From there I do not know how to continue and start coding it. So far from my understanding it requires me make a request data via uri but I'm stuck on how to actually code it. I'm wondering if anyone could point me to the right direction or provide a sample code that shows how to fetch data using URI.
I also downloaded the zipped Book API Jar libraries do I need to make use of this? I ask this because from a question on Google Places API on this website, one of the answer said that all you need is to use Google API as the build target and it doesn't require any Jar files but does this apply to Books API as well?
Also I'm using Eclipse, should I set my build target to be Google APIs 16? I'm guessing this is right since I plan to use Google Maps in future with this app.
Thanks this is first time I asked a question on here.
I just finished doing this myself. This is how I implemented it using an HttpURLConnection
and an AsyncTask
(I just call "https://www.googleapis.com/books/v1/volumes?q=isbn:"+yourISBN and parse the JSON):
// Received ISBN from Barcode Scanner. Send to GoogleBooks to obtain book information.
class GoogleApiRequest extends AsyncTask<String, Object, JSONObject>{
@Override
protected void onPreExecute() {
// Check network connection.
if(isNetworkConnected() == false){
// Cancel request.
Log.i(getClass().getName(), "Not connected to the internet");
cancel(true);
return;
}
}
@Override
protected JSONObject doInBackground(String... isbns) {
// Stop if cancelled
if(isCancelled()){
return null;
}
String apiUrlString = "https://www.googleapis.com/books/v1/volumes?q=isbn:" + isbns[0];
try{
HttpURLConnection connection = null;
// Build Connection.
try{
URL url = new URL(apiUrlString);
connection = (HttpURLConnection) url.openConnection();
connection.setRequestMethod("GET");
connection.setReadTimeout(5000); // 5 seconds
connection.setConnectTimeout(5000); // 5 seconds
} catch (MalformedURLException e) {
// Impossible: The only two URLs used in the app are taken from string resources.
e.printStackTrace();
} catch (ProtocolException e) {
// Impossible: "GET" is a perfectly valid request method.
e.printStackTrace();
}
int responseCode = connection.getResponseCode();
if(responseCode != 200){
Log.w(getClass().getName(), "GoogleBooksAPI request failed. Response Code: " + responseCode);
connection.disconnect();
return null;
}
// Read data from response.
StringBuilder builder = new StringBuilder();
BufferedReader responseReader = new BufferedReader(new InputStreamReader(connection.getInputStream()));
String line = responseReader.readLine();
while (line != null){
builder.append(line);
line = responseReader.readLine();
}
String responseString = builder.toString();
Log.d(getClass().getName(), "Response String: " + responseString);
JSONObject responseJson = new JSONObject(responseString);
// Close connection and return response code.
connection.disconnect();
return responseJson;
} catch (SocketTimeoutException e) {
Log.w(getClass().getName(), "Connection timed out. Returning null");
return null;
} catch(IOException e){
Log.d(getClass().getName(), "IOException when connecting to Google Books API.");
e.printStackTrace();
return null;
} catch (JSONException e) {
Log.d(getClass().getName(), "JSONException when connecting to Google Books API.");
e.printStackTrace();
return null;
}
}
@Override
protected void onPostExecute(JSONObject responseJson) {
if(isCancelled()){
// Request was cancelled due to no network connection.
showNetworkDialog();
} else if(responseJson == null){
showSimpleDialog(getResources().getString(R.string.dialog_null_response));
}
else{
// All went well. Do something with your new JSONObject.
}
}
}
protected boolean isNetworkConnected(){
// Instantiate mConnectivityManager if necessary
if(mConnectivityManager == null){
mConnectivityManager = (ConnectivityManager) getSystemService(Context.CONNECTIVITY_SERVICE);
}
// Is device connected to the Internet?
NetworkInfo networkInfo = mConnectivityManager.getActiveNetworkInfo();
if(networkInfo != null && networkInfo.isConnected()){
return true;
} else {
return false;
}
}
I've omitted the code for my dialog methods as they are not relevant. Hope this helps.
To access Google Books API or any other REST APIs directly at HTTP level, you can use Volley if you are willing to write asynchronous code, or OkHttp for simpler synchronous requests. And there's also Android Asynchronous Http Client.
But what's even better, you can use Feign or Retrofit that abstract away the HTTP-level implementation details and provide fluent typesafe APIs on top of auto-generated implementation. Retrofit is the most used network library in Android, but Feign is used more in the wider Java ecosystem.
Here's an example using Feign for Google Books API, Retrofit is very similar.
API interface, implementation is auto-generated by Feign:
public interface GoogleBooksApi {
@RequestLine("GET /books/v1/volumes")
Results findBookByISBN(@QueryMap Map<String, Object> queryParameters);
}
API client code:
public class BookLookupService {
public Book fetchBookByISBN(String isbn) throws BookLookupException {
final GoogleBooksApi googleBooksApi = connect();
final Map<String, Object> queryParameters = new HashMap<>();
queryParameters.put("q", "isbn:" + isbn);
final Results apiResponse = googleBooksApi.findBookByISBN(queryParameters);
if (apiResponse == null || apiResponse.getTotalItems() < 1) {
throw new BookLookupException("No books found for ISBN " + isbn);
}
final List<Result> results = apiResponse.getItems();
if (results == null || results.size() < 1) {
throw new BookLookupException("Invalid items list for ISBN " + isbn);
}
final Book book = results.get(0).getBook();
return book;
}
private static GoogleBooksApi connect() {
return Feign.builder()
.decoder(new GsonDecoder())
.logger(new Logger.ErrorLogger())
.logLevel(Logger.Level.BASIC)
.target(GoogleBooksApi.class, "https://www.googleapis.com");
}
}
Entities that model the API response structure:
public class Results {
int totalItems;
List<Result> items;
public int getTotalItems() {
return totalItems;
}
public List<Result> getItems() {
return items;
}
}
public class Result {
// the JSON field is named volumeInfo
Book volumeInfo;
public Book getBook() {
return volumeInfo;
}
}
public class Book {
private String title;
private List<String> authors;
public String getTitle() {
return title;
}
public List<String> getAuthors() {
return authors;
}
}
And last not least, test:
@RunWith(AndroidJUnit4.class)
public class BookLookupServiceAndroidTest {
private BookLookupService bookLookupService = new BookLookupService();
@Test
public void whenMultipleLookupResultsThenReturnsFirst() throws Exception {
assertThat(bookLookupService.fetchBookByISBN("9780321356680").getTitle(),
is(equalTo("Effective Java, 2nd Edition")));
}
}
Note that you need to wrap the code in AsyncTask
to make it asynchronous as network requests are not allowed on main thread. The AsyncTask
should update the UI in onPostExecute()
.
Here's an example:
public class MainActivity extends AppCompatActivity {
@Override
protected void onCreate(Bundle savedInstanceState) {
final Button fetchBookButton = (Button) findViewById(R.id.FetchBookButton);
fetchBookButton.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) { new FetchBookTask().execute(getISBN()); }
});
}
private String getISBN() {
final EditText isbnField = (EditText) findViewById(R.id.BookIsbnField);
return isbnField.getText().toString();
}
private void showMessage(String message) {
Toast.makeText(getApplicationContext(), message, Toast.LENGTH_LONG).show();
}
class FetchBookTask extends AsyncTask<String, Void, Book> {
@Override
protected Book doInBackground(String... params) {
final String isbn = params[0];
try {
return new BookLookupService().fetchBookByISBN(isbn);
} catch (Exception e) {
Log.e("fetchBookByISBN", e.toString());
return null;
}
}
@Override
protected void onPostExecute(Book book) {
if (book != null) {
showMessage("Got book: " + book.getTitle());
} else {
showMessage("Failed to fetch book");
}
}
}
}
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With