【问题标题】:Using Google Books API in Android在 Android 中使用 Google Books API
【发布时间】:2013-01-12 08:22:26
【问题描述】:

您好,我是 Android 新手,正在使用 Web API。我目前正在编写一个应用程序,它可以扫描一本书的条形码,然后在 Google 图书中搜索它。

到目前为止,我在我的应用程序中实现了 Scandit,并从 Google API 控制台为 Books API 注册并获取了 API 密钥。从那里我不知道如何继续并开始编码。到目前为止,据我所知,它需要我通过 uri 发出请求数据,但我一直坚持如何实际编码。我想知道是否有人可以指出正确的方向或提供一个示例代码来展示如何使用 URI 获取数据。

我也下载了zipped Book API Jar libraries 需要用这个吗?我问这个是因为从这个网站上关于 Google Places API 的一个问题中,答案之一说你所需要的就是使用 Google API 作为构建目标,它不需要任何 Jar 文件,但这是否适用于 Books API好吗?

我还在使用 Eclipse,我应该将构建目标设置为 Google APIs 16 吗?我猜这是对的,因为我计划将来在此应用中使用 Google 地图。

谢谢,这是我第一次在这里提问。

【问题讨论】:

标签: android google-api google-books


【解决方案1】:

我自己刚刚完成了这项工作。这就是我使用HttpURLConnectionAsyncTask 实现它的方式(我只需调用“https://www.googleapis.com/books/v1/volumes?q=isbn:”+yourISBN 并解析 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;
    }
}

我省略了对话方法的代码,因为它们不相关。希望这会有所帮助。

【讨论】:

  • 如果您要获取标题、缩略图、作者等,是否需要使用 API 密钥?
  • 您不需要密钥,只需要 URI。在浏览器中尝试:https://www.googleapis.com/books/v1/volumes?q=isbn:0307432866
  • 不过,您应该使用 API 密钥,请参阅 this question
  • 由于您不请求私人用户数据,因此您只需要 API 密钥,不需要进行 Oauth。以下是如何开始:link
  • 此 API 不返回图书的图片,而是在 Preview 中返回 HTML
【解决方案2】:

要直接在 HTTP 级别访问 Google Books API 或任何其他 REST API,如果您愿意编写异步代码,可以使用 Volley,或者对于更简单的同步请求,可以使用 OkHttp。还有Android Asynchronous Http Client

但更好的是,您可以使用 FeignRetrofit 抽象出 HTTP 级别的实现细节,并在自动生成的实现之上提供流畅的类型安全 API。 Retrofit 是 the most used network library in Android,但 Feign 在更广泛的 Java 生态系统中使用得更多。

这是一个使用 Feign for Google Books API 的示例,Retrofit 非常相似。

API 接口,实现由 Feign 自动生成:

public interface GoogleBooksApi {

    @RequestLine("GET /books/v1/volumes")
    Results findBookByISBN(@QueryMap Map<String, Object> queryParameters);

}

API 客户端代码

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");
    }
}

实体模拟 API 响应结构:

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;
    }
}

最后同样重要的是,测试

@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")));
    }
}

请注意,您需要将代码包装在AsyncTask 中以使其异步,因为主线程上不允许网络请求。 AsyncTask 应该更新 onPostExecute() 中的 UI。

这是一个例子:

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");
            }
        }
    }
}

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2013-01-19
    • 2019-08-18
    • 1970-01-01
    • 2023-03-22
    • 1970-01-01
    • 2018-12-18
    • 2021-10-22
    • 2019-06-21
    相关资源
    最近更新 更多