⾸先,这可能是⼀个⾮常罕⻅的优化,但咱们依然破费了⼤量的工夫和精⼒弄清楚这个优化的细 节, 所以我认为分享这个⼩优化是有意义的。期待有⼀天,某个地⽅的某个⼈可能会碰到雷同的问题,并从这篇⽂章中受害。

什么是反射?

反射⽤于察看并批改程序在运⾏时的⾏为。 ⼀个反射导向的程序组件能够监测⼀个范畴内的代码 执⾏状况, 能够依据获取的⽬标对象信息及与此相关的范畴批改⾃身。 这可通过在运⾏时动静分 配程序代码实现。

在类型检测严格的⾯向对象的编程语⾔如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 ClassClass classWallpaperManager = Class.forName("android.app.WallpaperManager");if(classWallpaperManager != null){//find its .getInstance(this) methodMethod methodGetInstance = classWallpaperManager.getDeclaredMethod("getInsta//invoke the WallpaperManager's .getInstance(this) method to get oneObject objWallpaperManager = methodGetInstance.invoke(classWallpaperManager,//discover the WallpaperManager Object's .getWallpaperInfo() MethodMethod methodGetWallpaperInfo = objWallpaperManager.getClass().getMethod("ge//invoke itObject objWallPaperInfo = methodGetWallpaperInfo.invoke(objWallpaperManager,if(objWallPaperInfo!=null){Log.d("WidgetDroid","WallpaperInfo not null");blurBackground=false;}}

同样为了确保安全调⽤, 咱们将它包装在⼀个疾速的 Android 版本检查和⼀个 try/catch 块中 以确保安全。

⼤功告成,当初如果设施使⽤的是动静壁纸,应⽤程序背景就不会含糊了,咱们的 Widget World 能够恢复正常。