如果對于 ARouter 不是很了解的,建議先行閱讀:
ARouter系列一:Activity跳轉(zhuǎn)原理詳解
ARouter系列二:@Autowired屬性注入
想要提供服務(wù)暴露給其他人使用,ARouter提供了一個(gè)接口:IProvider
// Provider interface, base of other interface.
public interface IProvider {
/**
* Do your init work in this method, it well be call when processor has been load.
*
* @param context ctx
*/
void init(Context context);
}
IProvider 只有一個(gè)方法 init, 參數(shù)為 Context。剛看到這接口的時(shí)候不是很明白,等把本篇文章看完之后就會明白,參數(shù)Context不可或缺。注意IProvider的注釋:IProvider是其它 Interface 的基礎(chǔ)??梢夾Router推薦的用法是 一個(gè)Interface 繼承 IProvider。
這里大家可能會有疑問,為什么需要Context參數(shù),為什么推薦是一個(gè)接口 繼承 IProvider,而不是實(shí)體類。帶著這些疑問,我們繼續(xù)探尋
一、使用
新建一個(gè)項(xiàng)目,有兩個(gè)moudle:app 和 location。location中封裝了地圖相關(guān)服務(wù),例如:開始定位,獲取位置等等。 app 依賴 location
1.1 location模塊
LocationService 定義此模塊提供的基礎(chǔ)服務(wù):開始定位 和 獲取地理位置。并且實(shí)現(xiàn)了 上述的 IProvider
package com.daddyno1.location;
public interface LocationService extends IProvider {
//開始定位
void startLocate();
//獲取經(jīng)緯度信息
Point getLocation();
}
BaiduLocationService 是提供服務(wù)的最終實(shí)現(xiàn)類。此處模擬使用了百度來實(shí)現(xiàn)具體功能。并且使用了 @Route(path = "/Loc/LocationService") 來標(biāo)注真實(shí) Location 服務(wù)實(shí)現(xiàn)類。
@Route(path = "/Loc/LocationService")
public class BaiduLocationService implements LocationService {
private static final String TAG = "BaiduLocationService";
@Override
public void startLocate() {
Log.i(TAG, "BaiduLocationService - startLocate");
}
@Override
public Point getLocation() {
return new Point(11,12);
}
@Override
public void init(Context context) {
Log.i(TAG, "BaiduLocationService - init");
}
}
編譯一下,我們看一下 apt 幫我們生成了哪些 輔助類:
ARouter$$Root$$location、ARouter$$Group$$Loc 和 ARouter$$Providers$$location,ARouter系列一:Activity跳轉(zhuǎn)原理詳解 的不難理解,ARouter$$Root$$location存儲了location module 下所有路由組信息;ARouter$$Group$$Loc 存儲了 location module 下 路由組名為 Loc 的路由表信息。
package com.alibaba.android.arouter.routes;
...
/**
* DO NOT EDIT THIS FILE!!! IT WAS GENERATED BY AROUTER. */
public class ARouter$$Root$$location implements IRouteRoot {
@Override
public void loadInto(Map<String, Class<? extends IRouteGroup>> routes) {
routes.put("Loc", ARouter$$Group$$Loc.class);
}
}
package com.alibaba.android.arouter.routes;
...
/**
* DO NOT EDIT THIS FILE!!! IT WAS GENERATED BY AROUTER. */
public class ARouter$$Group$$Loc implements IRouteGroup {
@Override
public void loadInto(Map<String, RouteMeta> atlas) {
atlas.put("/Loc/LocationService", RouteMeta.build(RouteType.PROVIDER, BaiduLocationService.class, "/loc/locationservice", "loc", null, -1, -2147483648));
}
}
ARouter$$Providers$$location 這個(gè)類長什么樣?我們來看一下:
package com.alibaba.android.arouter.routes;
...
/**
* DO NOT EDIT THIS FILE!!! IT WAS GENERATED BY AROUTER. */
public class ARouter$$Providers$$location implements IProviderGroup {
@Override
public void loadInto(Map<String, RouteMeta> providers) {
providers.put("com.daddyno1.location.LocationService", RouteMeta.build(RouteType.PROVIDER, BaiduLocationService.class, "/Loc/LocationService", "Loc", null, -1, -2147483648));
}
}
ARouter$$Providers$$location 這個(gè)類有什么用呢,我們先往后看,一會再說。
1.2 app模塊
這里新建一個(gè) Activity 使用我們創(chuàng)建好的 Location 服務(wù)
public class SecondActivity extends AppCompatActivity {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main3);
// 使用一:by name
LocationService locationService = (LocationService) ARouter.getInstance().build("/Loc/LocationService").navigation();
locationService.startLocate();
//使用二: by type
LocationService locationService1 = ARouter.getInstance().navigation(LocationService.class);
locationService1.startLocate();
}
}
我們運(yùn)行一下,看一下結(jié)果:
I: BaiduLocationService - init
I: BaiduLocationService - startLocate
I: BaiduLocationService - startLocate
注意: init 執(zhí)行了一次, startLocate 調(diào)用了兩次。
二、源碼分析
2.1 init
之前在分析Activity跳轉(zhuǎn)的時(shí)候分析了ARouter的初始化,這里不再細(xì)講。
public synchronized static void init(Context context, ThreadPoolExecutor tpe) throws HandlerException {
...
for (String className : routerMap) {
if (className.startsWith(ROUTE_ROOT_PAKCAGE + DOT + SDK_NAME + SEPARATOR + SUFFIX_ROOT)) {
//com.alibaba.android.arouter.routes.ARouter$$Root
// This one of root elements, load root.
((IRouteRoot) (Class.forName(className).getConstructor().newInstance())).loadInto(Warehouse.groupsIndex);
} else if (className.startsWith(ROUTE_ROOT_PAKCAGE + DOT + SDK_NAME + SEPARATOR + SUFFIX_INTERCEPTORS)) {
//com.alibaba.android.arouter.routes.ARouter$$Interceptors
// Load interceptorMeta
((IInterceptorGroup) (Class.forName(className).getConstructor().newInstance())).loadInto(Warehouse.interceptorsIndex);
} else if (className.startsWith(ROUTE_ROOT_PAKCAGE + DOT + SDK_NAME + SEPARATOR + SUFFIX_PROVIDERS)) {
//com.alibaba.android.arouter.routes.ARouter$$Providers
// Load providerIndex
((IProviderGroup) (Class.forName(className).getConstructor().newInstance())).loadInto(Warehouse.providersIndex);
}
}
...
}
唯一需要提一下的是,經(jīng)過路由器初始化之后,Warehouse的數(shù)據(jù)如下:


ARouter$$Providers$$location 這個(gè)是之前提到的apt生成的輔助類,它的作用就是幫助路由在初始化的時(shí)候,把相關(guān)數(shù)據(jù)注入到 Warehouse.providersIndex,這個(gè)有什么用呢,其實(shí)對于by name的使用方式來說,Warehouse.providersIndex 和 ARouter$$Providers$$location 根本沒用上,只是 by type 時(shí)候的輔助類。
2.2 by name
LocationService locationService = (LocationService) ARouter.getInstance().build("/Loc/LocationService").navigation();
2.3 by type
LocationService locationService1 = ARouter.getInstance().navigation(LocationService.class);
2.4 小結(jié)
具體的實(shí)現(xiàn)邏輯和 Activity 路由過程很相似,自己去看代碼吧。唯一的區(qū)別是,如果RouteType是 PROVIDER 的話,直接根據(jù)反射創(chuàng)建一個(gè)路由Destination 類的實(shí)例,存到Postcard里,最后返回給用戶。
本例中ARouter會使用反射創(chuàng)建一個(gè)BaiduLocationService 的實(shí)體對象,回調(diào)init方法,返回給使用者,之后把 實(shí)體對象緩存到 Warehouse.providers(Map<Class, IProvider>),下次直接在使用的話,直接從緩存獲取,不會再反射創(chuàng)建了。這也是本例為什么 init 只執(zhí)行了一次。
三、總結(jié)
1、為什么IProvider要提供一個(gè)Context?
我們知道ARouter是幫助我們實(shí)現(xiàn)項(xiàng)目組件化的工具,很多情況下一個(gè)Moudle是拿不到應(yīng)用程序Context的,本例中的場景就是。但很多服務(wù)的實(shí)現(xiàn)又會依賴于Context,所以有必要把Context傳遞給各個(gè)Moudle。
2、為什么推薦 Interface 集成 IPriovider?
ARouter說 通過依賴注入暴露服務(wù)。本例中抽象了一個(gè) LocationService 接口,此接口抽象了所有用到的服務(wù),用戶通過ARouter可以拿到 LocationService 的具體實(shí)現(xiàn)類,然后強(qiáng)轉(zhuǎn)成 LocationService 使用,可以不用關(guān)心具體的實(shí)現(xiàn)類是誰。這就是通過依賴注入的方式 實(shí)現(xiàn) 控制翻轉(zhuǎn),從而實(shí)現(xiàn)使用者 和 具體實(shí)現(xiàn)解耦的目的。假如某一天又想時(shí)候用 高德SDK 實(shí)現(xiàn)具體的 Location 服務(wù),使用者的代碼不用修改,實(shí)現(xiàn)完全的解耦。使用 高德 實(shí)現(xiàn) Location 服務(wù):
package com.daddyno1.location;
...
@Route(path = "/Loc/LocationService")
public class GaodeLocationService implements LocationService {
private static final String TAG = "GaodeLocationService";
@Override
public void startLocate() {
Log.i(TAG, " GaodeLocationService - startLocate");
}
@Override
public Point getLocation() {
return new Point(1,2);
}
@Override
public void init(Context context) {
Log.i(TAG, " GaodeLocationService - init");
}
}