您好我是Android新手并使用网络API。我目前正在编写一个应用程序,可以扫描书籍中的条形码,然后搜索Google Books。
到目前为止,我已将Scandit应用到我的应用程序中,并在Google API控制台中为Books API注册并获取了API密钥。从那里我不知道如何继续并开始编码。到目前为止,根据我的理解,它需要我通过uri发出请求数据,但我仍然坚持如何实际编码它。我想知道是否有人能指出我正确的方向或提供一个示例代码,说明如何使用URI获取数据。
我还下载了zipped Book API Jar libraries我需要使用它吗?我问这个问题是因为根据Google网站上的Google Places API问题,其中一个答案说您只需要使用Google API作为构建目标,它不需要任何Jar文件,但这适用于Books API好?
我也在使用Eclipse,我应该将构建目标设置为Google API 16吗?我猜这是对的,因为我计划将来使用谷歌地图这个应用程序。
谢谢这是我第一次在这里问一个问题。
答案 0 :(得分:5)
我刚刚完成了这个。这就是我使用HttpURLConnection
和AsyncTask
实现它的方式(我只是调用“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;
}
}
我省略了对话框方法的代码,因为它们不相关。希望这会有所帮助。
答案 1 :(得分:0)
要直接在HTTP级别访问Google Books API或任何其他REST API,如果您愿意为简单的同步请求编写异步代码或Volley,则可以使用OkHttp。还有Android Asynchronous Http Client。
但更好的是,您可以使用Feign或Retrofit抽象出HTTP级实现细节,并在自动生成的实现之上提供流畅的类型安全API。改造是the most used network library in Android,但是在更广泛的Java生态系统中更多地使用了Feign。
以下是使用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()
中的用户界面。
以下是一个例子:
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");
}
}
}
}