認真說的話, 這也算不上啥非官方API, 算是一個為了抓取Play store上資訊的一個小小工具: PlaystoreUtil

現在很多網路的服務, 大多有提供開放的REST API來供人寫原生的程式使用, 當然也有非常多並沒有, 像是Play store, 目前就沒開放的API可供存取, 剛好想要有個東西可以查詢某個app在play store上是屬於啥分類的, 所以就乾脆自己自製一個囉…

現在的網頁, 大多結構性很好, 所以就算沒有REST API, 其實也不難處理, 搭配上 jsoup , 可以說輕而易舉

jsoup是一個可以用css selector來解析html的Java函式庫, 有了這個, 解析html可以不用辛苦的爬dom tree, 只要幾行簡單的程式即可:

Document doc = Jsoup.connect("http://example.com/").get;

Elements links = doc.select("a[href]"); // a with href
Elements pngs = doc.select("img[src$=.png]");

再來看看play store

先看看每個app的資訊畫面, 以Facebook為例, 它的url是 –

https://play.google.com/store/apps/details?id=com.facebook.katana&hl=ja

很明顯的, id後面是package name, 另外如果加上"&hl=“可以指定語言, 然後再看到頁面上:

在Facebook (公司名稱)下方有個分類, 可以使用Chrome的開發人員工具(我比較習慣這個), 找到這個連結的css class名稱是”document-subtitle category“,而名稱則在它底下的一個span, 這span有個屬性itemprop, 值是genre

因此, 透過以下這段code就可以取到類別名稱囉

Document doc = Jsoup.connect("https://play.google.com/store/apps/details?id=" + packageName + "&hl=" + locale.getISO3Language()).get();
Elements elements = doc.select("span[itemprop=genre]");

當然, 這方法不只適用於play store, 其他網頁也可以嘗試用這個方法來取得資料

詳細的範例在: https://github.com/julianshen/PlaystoreUtil

Phantom.js好用的地方就是可以以下面這一段簡單的程式來抓取網頁的縮圖:

var page = require('webpage').create();
page.open('http://github.com/', function() {
  page.render('github.png');
  phantom.exit();
});    

結果是像這樣:

不過, 這邊要說的並不是Phantom.js, 而是在Android上怎像這樣抓網頁縮圖

在KitKat (API level 19)之前, WebView有capturePicture()這個API可以達成類似的效果, 不過, 這API在API level 19已經被deprecated掉了, 並且建議改用onDraw()

改用onDraw()其實也不太難, 只要在WebViewClient.onPageFinished()裡做:

    Bitmap mBitmap = Bitmap.createBitmap(view.getMeasuredWidth(), view.getMeasuredHeight(), Bitmap.Config.ARGB_8888);
    Canvas canvas = new Canvas(mBitmap);
    view.draw(canvas);

注意, 必須是在page finish之後才可以去做, 因為這時候網頁才算載入完畢, 不過結果有點不是很完美, 並非是整頁的

為了方便, 我寫成一個IntentService之後可以拿來重複利用:

WebThumbGrabber

寫成IntentService的好處是讓他可以在background thread去做, 前景的activity可以完全不用管它, 不過幾個webview的methods還是需要在main thread去跑, 為此, 在Service onCreate()引入了一個Handler, 為了避免IntentService在頁面還沒載入回來前就結束掉, 用了一個Semaphore來等待縮圖完成才結束整項工作

縮圖產生後, 必須要把產生的結果回傳給Activity, 這邊用的是"Activity.createPendingResult()“, 把產生的PendingIntent傳給IntentService來回傳結果, 這動作跟startActivityForResult類似, 回傳的結果也是由Activity.onActivityResult()來接收(可參考DemoActivity)

看到Square發表的這個Retrofit - http://bit.ly/167v72a 蠻有趣的, 它的目的似乎是試圖的想要去簡化開發REST client, 開發者不用寫太多的邏輯, 只要寫一個Interface跟利用annotation就可以完成一個簡單的REST client:

public interface GitHubService {
@GET("/users/{user}/repos")
List<Repo> listRepos(@Path("user") String user);
}

因為開發者只需要寫interface和annotation, 實質上並不用寫任何的code, 真正實作的部份他用了Proxy class的技巧包裝起來了, 這作法讓我想起來很久之前我在之前的工作幫公司寫的一個legacy系統的wrapper, 那時有很多機器產生的interface, 如果人工一個個實作很浪費時間, Proxy class可以解決掉這一部分的問題, 同樣的在retrofit似乎也是想用這技巧節省實作

但可惜的是, 現在的retrofit並還沒加入OAuth的支援, 因此送出去的API部分並沒被oauth簽章過,不過所幸要解決這一部分也不難, 寫一個Client class搭配Signpost還是可以做到, 這邊範例繼承了OkClient(使用OkHttp) :



因為OkHttp也是一種HttpURLConnection, 因此Signpost搭配DefaultOAuthProvider和DefaultOAuthConsumer即可, 另外初始化RestAdapter時加上這個新的Client即可:

RestAdapter restAdapter = new RestAdapter.Builder() .setClient(new SignedOkClient(mConsumer))


via Blogger http://bit.ly/11OBeFb

前一篇寫了一個自訂義的layout - SimpleCellLayout, 前一個版本的問題就是, 必須是寫程式把child view加進這個layout之中, 而且針對像是欄與行的數目也必須在程式裡設定, 並無法寫到layout xml中, 所以這次的目邊就是要讓這個layout可以像下面這樣用layout xml來擺佈:


在這範例之中, 用到幾個像是col, row, gapsize, cellX這些在原生Android並不存在的屬性, 為了這些屬性, 就需要定義一個attrs.xml在res/values目錄內, attrs.xml 裡面要定義的就是這些樣式描述屬性, 這邊定義了: 給SimpleCellLayout本身用的col(欄數), row(行數), gapsize(間距大小), 以及給他的Child views用的cellX(格子的橫軸位置), cellY(格子的縱軸位置), colspan(格子寬), rowspan(格子高), 除了gapsize我們需要的跟實際螢幕上的大小有關, 所以格式定義為dimension外(就是可以用3dp, 1px這類的值), 其他都是整數就可

這些屬性, 到時候就是要放在xml標籤內的屬性

要用到這些屬性, 需要先在tag裡面定義一個新的name space, 如同在前面範例寫的:

xmlns:celllayout=“http://bit.ly/GEGVYd”
文件內的範例大多是apk/後面接著package name, 不過Android Studio卻是建議使用"res-auto", 定義了這個name space後, 便可以在後面的tag內使用像是"celllayout:col"這樣的屬性了

那在layout內又要怎處理這些屬性? ViewGroup有兩個建構子所需要帶的參數含有AttributeSet, 基本上只要從這兩個建構子處理就好

這範例內的initFromAttributes就是用來從AttributeSet擷取這些屬性, 前面attrs.xml有定義stylable, 所以基本上有一堆相對應的Resource ID可以使用,這邊只處理了col, row, 和gapsize, 因為只有這三個屬性直接跟這layout相關, 至於這layout的child views該怎處理呢? 它就要靠LayoutParams了, 我在SimpleCellLayout內定義了一個CellLayoutParams, 基本上這類別也有一個建構子是用來處理AttributeSet的


這邊比較重要的就是要overwrite掉generateLayoutParams, 因為ViewGroup原有的generateLayoutParams實作的是回傳ViewGroup.LayoutParams, 他並不認得CellLayoutParams, 但SimpleCellLayout靠的是CellLayoutParams來儲存layout所需的資訊, 原本用程式來加入view的範例部份, 我是手動產生一個CellLayoutParams來給child view, 但如果是放在layout xml, 並無法指定要用哪個LayoutParams類別, 這時候就要靠generateLayoutParams了 有趣的是, 雖然是我自訂的layout, 但在我做完這些後, Android studio的UI編輯器, 卻知道怎去依據我的layout把元件畫到正確的位子上面:



via Blogger http://bit.ly/1af6KAB

寫Android寫了這麼久, 才想到自己沒寫過custom layout, 剛剛花了點時間(主要時間還是花在跟Android studio和gradle搏鬥)寫了一個簡單的CellLayout (還很陽春) :

http://bit.ly/12nuhGn

寫custom layout還蠻簡單的, 在onMeasure決定自己和child views的大小, 在onLayout時把每個child views放到適當的位置, 目前還沒加入attibrtues的支援, 所以暫時還只能寫code自己把view加進去, 另外也還沒加檢查是不是會有重疊的views, 之後再來寫

這個layout跟GridView不同, 可以不用每個格子都是同一大小, 以下範例是把畫面劃成4x4的格子, 左上角的那張圖大小是2x2, 下方則是 4x2





via Blogger http://bit.ly/12nuj0X