⾸先,這可能是⼀個⾮常罕⻅的優化,但我們仍然花費了⼤量的時間和精⼒弄清楚這個優化的細 節, 所以我認為分享這個⼩優化是有意義的。期待有⼀天,某個地⽅的某個⼈可能會碰到相同的問題,並從這篇⽂章中受益。
什麼是反射?
反射⽤於觀察並修改程式在運⾏時的⾏為。 ⼀個反射導向的程式元件可以監測⼀個範圍內的程式碼 執⾏情況, 可以根據獲取的⽬標物件資訊及與此相關的範圍修改⾃身。 這可通過在運⾏時動態分 配程式程式碼實現。
在型別檢測嚴格的⾯向物件的程式設計語⾔如Java中, ⼀般需要在編譯期間對程式中需要調⽤的對 象的具體型別、 接⼝ (interface) 、 資料成員 (fields) 和⽅法的合法性進⾏檢查。 反射技術則 允許將對需要調⽤的物件的訊息檢查⼯作從編譯期間推遲到運⾏期間再現場執⾏。
這樣⼀來,可以在編譯期間先不明確⽬標物件的接⼝(interface)名稱、 欄位(fields) , 即物件的資料成員 (成員變數) 、 可⽤⽅法, 然後在運⾏根據⽬標物件⾃身的訊息決定如何處理。 它 還允許根據判斷結果進⾏例項化新物件和相關⽅法的調⽤。
為什麼會出現這個問題?
我們⼀直收到投訴, ⽤戶聲稱啟⽤動態桌布後, 我們的 Buzz ⼩部件在紅⽶Note 5上滯後。 為 了復現此問題, 我們使⽤友盟+U-APM在紅⽶Note 5上進⾏線上測試, 同時使⽤⾃定義異常丟擲問題。
測試表明, 這個異常是通過
WallpaperManager.getInstance(this).getWallpaperInfo()
的if
程式碼觸發的,也就是說這是由於應⽤程式模糊了桌⾯,並試圖在桌⾯上呈現內容導致的問題。 如果桌⾯上運⾏著動態桌布,那麼模糊它會造成⼀些週期性的處理器消耗。
為什麼要使用反射,而不是API?
我更希望我們的每個應⽤程式在 Android Market 中只有⼀個版本,⽽⽤於此的 API 僅在⼀部 分 SDK 中可⽤。 反射使我們能夠使⽤ API, 同時仍然讓應⽤程式在具有較舊韌體的裝置上運⾏。
如何解決?
好了, 我們要開始展示解決⽅案了
if(WallpaperManager.getInstance(this).getWallpaperInfo() != null){//不模糊}
要使⽤反射來做到這⼀點,我們必須使⽤Class.forName("")
、Class.getDeclaredMethod()
、Object.invoke()
⽅法,有點像這樣
boolean blurBackground = true;
//get the WallpaperManager Class
Class classWallpaperManager = Class.forName("android.app.WallpaperManager");
if(classWallpaperManager != null)
{
//find its .getInstance(this) method
Method methodGetInstance = classWallpaperManager.getDeclaredMethod("getInsta
//invoke the WallpaperManager's .getInstance(this) method to get one
Object objWallpaperManager = methodGetInstance.invoke(classWallpaperManager,
//discover the WallpaperManager Object's .getWallpaperInfo() Method
Method methodGetWallpaperInfo = objWallpaperManager.getClass().getMethod("ge
//invoke it
Object objWallPaperInfo = methodGetWallpaperInfo.invoke(objWallpaperManager,
if(objWallPaperInfo!=null)
{
Log.d("WidgetDroid","WallpaperInfo not null");
blurBackground=false;
}
}
同樣為了確保安全調⽤, 我們將它包裝在⼀個快速的 Android 版本檢查和⼀個 try/catch
塊中 以確保安全。
⼤功告成,現在如果裝置使⽤的是動態桌布,應⽤程式背景就不會模糊了,我們的 Widget World
可以恢復正常。