這套 Library 對我來說的好處是
- 很方便的切換不同的 HTTP Method,不必每次要換 Method 都需要重寫很多源碼
- 自己處理瑣碎的事情,像是 gzip 壓縮, 傳入傳出 JSON 的 String-Object 轉換,URL builder 這些都很方便
- 減少源碼,有了上述的東西,源碼行數當然是大幅減少了。
另外它還有些特性我不太用到像是同時支援 JSON, XML、同時 support GAE, J2SE/J2EE 跟 Android,甚至可以替換 HTTP Client、Json library 或 XML library。
話說他的名字可能會讓你覺得這是一套給 Google APIs 專門使用的 client library,其實不然。除了可以透過它存取 Google Services,也可以利用它來建構自己的 client library。如果要初步的了解這套 library 可以先看 Google I/O 2011: Best Practices for Accessing Google APIs on Android,這篇裡面有些使用他的基本知識。
安裝很簡單,就直接照著 README 的說明,把該丟的 jar 檔放到 libs 裡面就行了。因為它同時支援 google app engine, Java SE, 跟 Android 開發環境,所以不同的狀況底下會有不同的 dependency,你可以參考我丟的 jar:
你可能剛開始就被它龐大的相依 library 嚇到了,事實上它可以透過 proguard 在 release app 的時候去除掉那些你從沒用到的地方,在 Yaniv Inbar 的投影片裡面也有提到它在他的例子中可以節省 95% 的空間。
怎麼樣開始用 Google APIs Client 寫自己的 APi wrapper 呢?下面參考 Google Task 跟 Google+ 的 API 提供了一個簡單的範本
package idv.yurenju.google.sample; import java.io.IOException; import com.google.api.client.http.HttpMethod; import com.google.api.client.http.HttpResponse; import com.google.api.client.http.HttpTransport; import com.google.api.client.http.json.JsonHttpClient; import com.google.api.client.http.json.JsonHttpRequest; import com.google.api.client.json.JsonFactory; import com.google.common.base.Preconditions; public class SampleClient extends JsonHttpClient { public static final String DEFAULT_BASE_URL = "https://api.twitter.com/"; public SampleClient(HttpTransport transport, JsonFactory factory) { super(transport, factory, DEFAULT_BASE_URL); } }
DEFAULT_BASE_URL 是 web service 基礎的網址,往後所有的 query 都會基於這個網址。當建立你的 Client 的時候,你可以任意的替換 HttpTransport 與 JsonFactory。這邊我們用的是 NetHttpTransport 跟 JacksonFactory。
SampleClient client = new SampleClient(new NetHttpTransport(), new JacksonFactory());
要開始寫頭一個 API 時,首先要先建立 Data Model,這邊我們先用 Twitter 的 user_timeline 測試。用 http://api.twitter.com/1/statuses/user_timeline/yurenju.json 可以獲得我的 twitter 訊息。而每個 tweet 物件的屬性非常多,我們先用 text 與 created_at 這兩個訊息來測試。 在這邊建立 TweetModel 如下:
package idv.yurenju.google.sample; import com.google.api.client.json.GenericJson; public class TweetModel extends GenericJson { @com.google.api.client.util.Key("text") private String mText; @com.google.api.client.util.Key("created_at") private String mCreatedAt; public String getText() { return mText; } public void setText(String mText) { this.mText = mText; } public String getCreatedAt() { return mCreatedAt; } public void setCreatedAt(String mCreatedAt) { this.mCreatedAt = mCreatedAt; } }
重點其實是繼承 GenericJson,而 6-10 行主用的功能是協助我們把 text, created_at mapping 到符合 Android 寫作風格的 mText, mCreatedAt,剩下的部份則是 setter/getter。接下來就可以在 SampleClient 裡面加入 API。
package idv.yurenju.google.sample; import java.io.IOException; import com.google.api.client.http.HttpMethod; import com.google.api.client.http.HttpResponse; import com.google.api.client.http.HttpTransport; import com.google.api.client.http.json.JsonHttpClient; import com.google.api.client.http.json.JsonHttpRequest; import com.google.api.client.json.JsonFactory; import com.google.common.base.Preconditions; public class SampleClient extends JsonHttpClient { public static final String DEFAULT_BASE_URL = "https://api.twitter.com/"; public SampleClient(HttpTransport transport, JsonFactory factory) { super(transport, factory, DEFAULT_BASE_URL); } public Users users() { return new Users(); } public class Users { public GetTimeline getTimeline(String screenname) throws IOException { GetTimeline get = new GetTimeline(screenname); initialize(get); return get; } public class GetTimeline extends JsonHttpRequest { private static final String REST_PATH = "1/statuses/user_timeline/{screenname}.json"; @com.google.api.client.util.Key("screenname") private String mScreenName; private GetTimeline(String screenname) { super(SampleClient.this, HttpMethod.GET, REST_PATH, null); Preconditions.checkNotNull(screenname); mScreenName = screenname; } public TweetModel[] execute() throws IOException { HttpResponse response = executeUnparsed(); TweetModel[] result = response.parseAs(TweetModel[].class); return result; } } } }
32 行提供了 REST 所用的 Path,其中 screenname 是會將變數替代入 Path 的參數,34-35 行的工作就是將 mScreenName mapping 到 screenname。當你設定了 mScreenName 後,執行 query 時就會帶入到 {screenname}。
37-41 行的建構子,在這邊可以指定要用的 Http Method 以及要放入 Body 的變數。在這邊我們使用 null 原因是因為 GET Method 不需要填任何東西在 Body,但是使用 POST Method 的時候這邊通常就會把 JSON object 填入。
43-48 行是真正執行 query 的地方。這個時候它會取得 Response,並且將內容用 TweetModel 陣列的方式剖析,最後回傳 TweetModel[]。
25-29 行的地方做了 Reuqest 的 initialize,如果你有需要對 header 作手腳的話可以在這邊弄。
完成了 Client 之後,最後就可以利用以下的方法來調用 getTimeline 的 API:
TweetModel[] tweets = client.users().getTimeline("yurenju").execute(); for (TweetModel tweet : tweets) { Log.i("SAMPLE", tweet.getText()); }
接下來如果有意外的話(咦)我會繼續講解 POST, PUT, modify headers 跟 authentication 的部份。