HTTP レベルで直接 Google Books API やその他の REST API にアクセスするには、非同期コードを記述したい場合はVolleyを使用し、より単純な同期リクエストにはOkHttpを使用できます。Android Asynchronous Http Clientもあります。
しかし、さらに良いことに、HTTP レベルの実装の詳細を抽象化し、自動生成された実装の上に流暢なタイプセーフ API を提供するFeignまたはRetrofitを使用できます。Retrofit は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;
}
}
そして最後に、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")));
}
}
AsyncTask
メインスレッドではネットワークリクエストが許可されていないため、非同期にするためにコードをラップする必要があることに注意してください。のAsyncTask
UI を更新する必要があり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");
}
}
}
}