程式設計師不可以錯過的Android元件化神器-ServicePool!
介紹
元件化開發過程中,隨著元件越來越多,元件的之前的互動就會變得非常的複雜,此時元件間通訊變得尤其的重要,
ServicePool
就是為元件化而生,用最簡單的方式進行元件間通訊。
使用依賴注入,按需靈活注入元件。同時支援元件熱插拔,達到元件即插即用的效果。可配置元件生命週期,做到元件按需建立和及時回收,充分利用懶載入的思想,有效解決元件初始化耗時導致的
app
啟動速度問題。
ServicePool
包含有
Activity
路由, 元件路由等等最常用的元件化能力。除此之外,元件化開發過程中有沒有遇到過想使用某個已有的類,比如一個工具類的時候,發現這個工具類在當前類的上層,無法直接依賴和引用,而修改這個工具類的層級又會牽一髮而動全身的問題?有沒有想要一個差異響應的能力,在不同的元件中或者環境下,有著不同的響應方式?有沒有想要一個自適應場景的能力,自動適應當前環境(比如
Java
還是
Android
環境,比如
Debug
環境還是
Release
環境等等),從而使用最合適的功能。又有沒有想過如何讓元件做到像USB介面一樣插上就能直接使用,拔掉也不影響主體功能的即插即用的效果。等等...。下面就來具體介紹一下這個元件化神器——
ServicePool
!
ServicePool基礎能力
如上圖所示:
- 元件
A
,B
是兩個互不依賴的元件,A
,B
不能直接通訊 - 元件
A
,B
分別透過AService
,BService
對外提供服務 - 元件
A
,B
的介面協議存放在元件服務池pool
, 分別是介面IA, IB - 當元件B需要元件A的服務時,元件B使用IA介面向
ServicePool
申請, 由ServicePool
建立並返回aService
給元件B, 此時元件b
可以使用aService
的服務了 - 同理, 元件
A
使用IB
向ServicePool
申請bService
-
aService
,bService
由ServicePool
建立和管理 - 所有
Service
物件的優先順序生命週期可以透過@Service
註解配置
/** * 服務池pool中 * * IA.java */ public interface IA { void aName(); } /** * 服務池pool * * IB.java */ public interface IB { void bName(); }
/** * 元件A * * AService.java */ @Service public class AService implements IA { @Override public String aName() { return "A Service"; } }
/** * 元件B * * BService.java */ @Service public class BService implements IB { @Override public String bName() { return "B Service"; } }
元件A中執行: IB b = ServicePool.getService(IB.class); System.out.println("I'm A Service, I can get " + b.bName()); 輸出: I'm A Service, I can get B Service 元件B中執行: IA a = ServicePool.getService(IA.class); System.out.println("I'm B Service, I can get " + a.aName()); 輸出: I'm B Service, I can get A Service
依賴注入(DI)
由於所有示例涉及到依賴注入,這裡提前對
ServicePool
的依賴注入做個說明。和其他注入框架不同,
ServicePool
的注入方式很簡單,只有一種注入方式就是直接透過類注入。
@Service public class AImpl implements IA { @Override public String aName() { return "A Impl" } }
ServicePool
就是一個注入容器。最後透過
ServicePool
.
getService(IA.class)
方法注入物件, 也可以透過
@Service
標記成員變數的方式注入,這兩個方法等價。
public class MainActivity extends AppcompatActivity { /** * 等價於 * IA = ServicePool.getService(IA.class); */ @Service private IA a; @Override public void onCreate(Bundle savedInstanceState) { System.out.println(a.getName()); //輸出 A Service } }
ServicePool
注入物件時,會根據
Service
配置的生命週期型別
(scope)
和優先順序來決定當前是建立還是直接返回快取物件。
指定Service優先順序,按優先順序順序返回
如果IA有多個實現,如上圖所示,
ServicePool
會比較每個實現優先順序,來決定最
終返回IA的哪個實現
-
@Service
註解標記一個實現類時候可以透過引數priority指定這個實現類的優先順序 - 優先順序值越大優先順序越高,
ServicePool
預設會返回優先順序最高的實現類物件 - 如果多個實現類優先順序相同,那麼返回會有不確定性
- 也可以直接指定具體使用哪個實現類,如
ServicePool
.getService(AService1.class)
將會返回一個AService1
物件
/** * 服務池pool中 * * IPriorityService.java */ public interface IPriorityService { int getPriority(); }
/** * 元件A中 * * PriorityService1.java * PriorityService2.java */ @Service(priority = 1) public class PriorityService1 implements IPriorityService { @Override public int getPriority() { return 1; } } @Service(priority = 2) public class PriorityService2 implements IPriorityService { @Override public int getPriority() { return 2; } }
元件B中執行: IPriorityService priorityService = ServicePool.getService(IPriorityService.class); System.out.println("priority is " + priorityService.getPriority()); priorityService = ServicePool.getService(PriorityService1.class); System.out.println("priority is " + priorityService.getPriority()); priorityService = ServicePool.getService(PriorityService2.class); System.out.println("priority is " + priorityService.getPriority()); 輸出: priority is 2 priority is 1 priority is 2
典型應用場景
-
Java Library
元件和Android Library
元件使用不同的服務, 如classloader
等等。 -
debug
環境,release
環境或者不同的productFlavor
使用不同的服務, 如logger
,Mock
等等 - 不同的業務場景使用不同的服務
給服務物件指定生命週期
每個由
ServicePool
建立的
service
物件都有各自生命週期,
service
物件的生命週期由
ServicePool
管理, 並由
@Service
註解配置生命週期型別。
-
Service
有once
,temp
,global
三種生命週期型別. - 指定
Service
的生命週期為once
,@Service(scope=IService.Scope.once)
,每次ServicePool.getService()
都會建立一個新的物件,物件使用後隨gc
自動被回收,scope
預設為once
- 指定
Service
的生命週期為temp
,@Service(scope=IService.Scope.temp)
,Service
由WeakReference
快取,只適用無狀態服務。 - 指定
Service
的生命週期為global
,@Service(scope=IService.Scope.global)
,每次ServicePool.getService()
拿到的都是同一個物件,App
執行期間不會被回收
元件A中 /** * * OnceService.java */ @Service(scope = IService.Scope.once) public class OnceService implements LifecycleService { } /** * * TempService.java */ @Service(scope = IService.Scope.temp) public class TempService implements LifecycleService { } /** * * GlobalService.java */ @Service(scope = IService.Scope.global) public class GlobalService implements LifecycleService { }
元件B中執行: System.out.println(ServicePool.getService(OnceService.class) == ServicePool.getService(OnceService.class));//System.out.println(ServicePool.getService(TempService.class) == ServicePool.getService(TempService.class));//不可靠 System.out.println(ServicePool.getService(GlobalService.class) == ServicePool.getService(GlobalService.class));輸出:falsetrue
支援透過path查詢Service
/** * 服務池pool中 * * IPathService.java */ public interface IPathService { String pathServiceName(); }
/** * 元件A中 * * PathService */ @Service(path = "pathService") public class PathService implements IPathService { @Override public String pathServiceName() { return "Path Service"; } }
IPathService
是任意定義的介面,它可以有一個或多個實現類,只要在實現類上加
@Service
註解並指定
path
屬性。我們就可以透過
ServicePool.getService(path)
來找到或者建立他的實現類物件。
元件B中執行: IPathService pathService = ServicePool.getService("pathService"); System.out.println(pathService.pathServiceName()); 輸出: Path Service
典型應用場景:
-
activity
路由 - 混合開發中,可以透過
path
將橋接方法分發到對應執行器
元件初始化
app
開發過程中,肯定少不了對元件進行初始化,無論是內部元件還是引用外部庫,很多都需要執行初始化操作。常規的方式是所有初始化操作都是放到
Application
的
onCreate()/onAttachBaseContext()
方法中執行。元件有很多而
Application
只有
1
個, 如何讓每個元件都可以擁有它自己的初始化類呢?
ServciePool
中有一個
@Init
註解,任何被
@Init
註解標記的
Service
類被認為是一個需要執行操作初始化操作的
Service
類, 同時這個
Service
類需要實現
IInitService
介面。
@Init(lazy = false) //lazy = false表示禁用懶載入,則該Service會隨Application初始化而初始化 @Service public class InitService implements IInitService { @Override public void onInit() { //do something. } }
如果初始化元件想要隨
Application
初始化而初始化,需要將
@Init
註解的
lazy
賦值為
false
,表示禁用懶載入。除了
lazy
屬性,
@Init
註解還有
async
,
dependencies
兩個屬性。
async
屬性顧名思義是非同步執行,
async
預設為
false
,設定為
true
表示該元件初始化會在非同步執行緒執行。
dependencies
可以傳遞一個初始化元件類陣列,表示當前元件初始化依賴這個陣列中的所有元件。
ServicePool
會先初始化陣列中的元件再去執行當前元件的初始化。
@Init @Service public class InitService1 implements IInitService { @Override public void onInit() { System.out.println("Service 1 Inited!!!"); } } @Init @Service public class InitService2 implements IInitService { @Override public void onInit() { System.out.println("Service 2 Inited!!!"); } } @Init(lazy = false, dependencies=[InitService1.class, InitService2.class]) @Service public class InitService3 implements IInitService { @Override public void onInit() { System.out.println("Service 3 Inited!!!"); } }
ServicePool
的初始化在
這篇文章的最後中有實際應用,也可做為示例參考。
元件懶載入機制 & 禁用懶載入
所有初始化操作都隨
Application
啟動執行,一方面會導致
Application
非常臃腫,另一方面雖然單個元件初始化時長很短,但
n
多個元件初始化時長結合在了一起就會導致啟動時間超長。懶載入是
ServicePool
的核心思想。所有元件只有在第一次被使用時才會被建立和執行初始化。而不是集中在
Application
初始化過程。分散初始化從而減輕
App
啟動壓力。舉個?微信分享是很常用的功能,我們以微信分享為例,
WXShareManager
用來助力微信分享相關操作。
@Init @Service public class WXShareManager implement IInitService { public static final String appId = "wx499fa9b1ba4a93db"; public static final String userName = "gh_6619a14a139d"; @Override public void onInit() { IWXAPI wxApi = WXAPIFactory.createWXAPI(mContext, null); wxApi.registerApp(appId); } public void share(...) { //do wx share. } }
shareManager
注入物件的時候初始化操作會被執行。
public class ShareActivity extends AppcompatActivity { @Service private WXShareManager shareManager;//此時會觸發WXShareManager的onInit初始化。 ... void onClick(View v) { shareManager.share(...); } }
元件熱插拔
未完待續....
Activity路由
未完待續....
來自 “ ITPUB部落格 ” ,連結:http://blog.itpub.net/69952849/viewspace-2674207/,如需轉載,請註明出處,否則將追究法律責任。
相關文章
- UI設計師:你不能錯過的七大神器!UI
- 程式設計師不可以錯過的寶藏地方,2020 還不會泡GitHub? 你落伍了!程式設計師Github
- 程式設計師跳槽必備神器程式設計師
- 程式設計師薅羊毛神器來了!程式設計師
- 讓程式設計師不再苦逼的神器(上)程式設計師
- 讓程式設計師不再苦逼的神器(下)程式設計師
- 創業者,程式設計師必備神器創業程式設計師
- reveal.js - 程式設計師的PPT製作神器JS程式設計師
- 推薦幾個好用的程式設計師效率神器程式設計師
- 那些 Android 程式設計師必會的檢視優化策略Android程式設計師優化
- 不可以錯過的Android學習!帶你看Android Jetpack 最佳開發姿勢!AndroidJetpack
- 程式設計師最喜歡的五大神器程式設計師
- vue - Vue元件化程式設計Vue元件化程式設計
- 【程式設計師的實用工具推薦】 Mac 效率神器 Alfred程式設計師MacAlfred
- 黑馬程式設計師Android實戰影片教程等,超過30程式設計師Android
- 關於 Android 程式設計師最近的狀況Android程式設計師
- 推送——Android程式設計師‘一生的痛’!!Android程式設計師
- 35歲,程式設計師過不去的坎?程式設計師
- 程式設計師的中年該如何度過程式設計師
- 我常用的兩個翻譯神器!程式設計師必備 | JavaGuide程式設計師JavaGUIIDE
- 以前的程式設計師,現在的程式設計師程式設計師
- Android 架構設計:MVC、MVP、MVVM和元件化Android架構MVCMVPMVVM元件化
- 程式設計師的職業生涯可以有哪些出路?這些路子別錯過程式設計師
- 好程式設計師web前端分享透過Vue插槽的元件傳遞HTML內容程式設計師Web前端Vue元件HTML
- 程式設計師過年的無奈與不甘程式設計師
- 淺談程式設計師的“內卷化”程式設計師
- 你見過背誦程式碼的程式設計師嗎?程式設計師
- 程式設計師與「中臺」的愛恨交錯程式設計師
- 程式設計師面試能力通過,卻被技術主管拒絕,HR回覆原因,程式設計師以為聽錯了程式設計師面試
- 看80萬程式設計師評論:可不可以用中文寫程式碼程式設計師
- DevToys Mac程式設計師神器,號稱開發者的瑞士軍 刀devMacC程式程式設計師
- FastReport VCL程式設計師手冊:使用TfrxReport元件AST程式設計師元件
- Android程式設計師的Java後臺學習建議Android程式設計師Java
- 美女程式設計師觀點:程式設計師最重要的非程式設計技巧程式設計師
- CodeRunner 3 for Mac程式設計神器MacC程式程式設計
- 怎麼從初、中級Java程式設計師過渡到高階Java程式設計師?Java程式設計師
- 普通程式設計師和厲害程式設計師的差距!程式設計師
- 6個程式設計實戰網站,想學程式設計的你不能錯過!程式設計網站