在之前的組件化開發中,如果ModuleA想要調用另一個ModuleB中的類或者方法,只能通過添加依賴的方式,而且是強依賴;這種形式存在的一個問題就是:如果ModuleB中的類發生改變,那麼ModuleA也需要改變該類,甚至該類已經無法繼續使用了,擴展性不強,耦合性太高。
但是開源的ARouter路由就解決了這個問題,Module之間不再是處於強耦合的關係,而是使用ARouter作爲中間人,所有的Module在ARouter中註冊後,那麼其他的Module都可以調用ARouter中該Module的類和方法,而且Module在ARouter中註冊之後,不管Module中怎麼改變,其他獲取到仍然是之前的類,不會因爲其他的Module改變而需要去改變。
例如Module在ARouter註冊一個類 B.a,ModuleA調用這個類,ModuleB此後將B.a改成了B.c,那麼其他Module調用的依然是B.a,並不受ModuleB改變受到影響。
1、ARouter的基礎使用
《阿里巴巴ARouter手冊》具體使用可以從這裏獲取更多,還有源碼解析等,這裏主要講解ARouter的主要用法。
(1)依賴配置
在defaultConfig
以及dependencies
中添加以下依賴
javaCompileOptions {
annotationProcessorOptions {
arguments = [moduleName: project.getName()]
}
}
implementation 'com.alibaba:arouter-api:1.3.1'
annotationProcessor 'com.alibaba:arouter-compiler:1.1.3'
(2)Activity之間的跳轉
在之前沒有使用ARouter的時候,使用Activity之間跳轉的方式是通過startActivity的方式,尤其是使用顯示意圖Intent跳轉的時候,耦合性太高。
在使用ARouter時,首先需要在Application中註冊初始化之後,纔可以使用
//初始化ARouter
if(isDebug()){
ARouter.openLog();
ARouter.openDebug();
}
ARouter.init(this);
現在就可以實現Activity之間的跳轉了,在當前Activity中,如果想要跳轉到目標Activity,只需要以下一行代碼即可。
btn_jump.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
ARouter.getInstance().build(Router.MAIN_ACTIVITY).navigation();
}
});
build中,代表跳轉的目標Activity,所以在目標Activity中,需要使用@Route註解來註釋。
@Route(path = Router.MAIN_ACTIVITY)
public class MainActivity extends AppCompatActivity {
private Handler handler = new Handler();
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
//注入
ARouter.getInstance().inject(this);
}
}
一旦使用註解,那麼就需要將ARouter注入!!!
(3)Activity攜帶參數跳轉
在ARouter提供的API中,可傳遞的數據類型和Intent基本一致:基本數據類型、可序列化數據(2種)。。。
ARouter.getInstance()
.build(Router.MAIN_ACTIVITY)
.withString("name","ClearLove")
.withInt("age",12)
.navigation();
目標Activity:
@Route(path = Router.MAIN_ACTIVITY)
public class MainActivity extends AppCompatActivity {
private TextView tv_name,tv_age;
@Autowired(name = "name") //這裏可以不用寫,因爲攜帶的key是一致的
String name; // String mName; 如果這樣聲明就需要加name
@Autowired()
int age;
private Handler handler = new Handler();
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
//注入
ARouter.getInstance().inject(this);
tv_name = findViewById(R.id.tv_name);
tv_age = findViewById(R.id.tv_age);
tv_name.setText(name);
tv_age.setText(age+"");
}
}
通過@Autowired
註解來修飾,需要注意的是,如果攜帶數據的key一致,在@Autowired
不需要聲明name。
(4)Uri跳轉
Uri uri = Uri.parse(Router.MAIN_ACTIVITY);
ARouter.getInstance()
.build(uri)
.withString("name","ClearLove")
.withInt("age",12)
.navigation();
(5)動畫
Uri uri = Uri.parse(Router.MAIN_ACTIVITY);
ARouter.getInstance()
.build(uri)
.withTransition(Animation.REVERSE,Animation.ZORDER_TOP)
.withString("name","ClearLove")
.withInt("age",12)
.navigation();
使用withTransition
可以設置入場動畫和出場動畫,來設置跳轉動畫。
(6)路由回調 NavigationCallback
ARouter.getInstance()
.build(uri)
.withTransition(Animation.REVERSE,Animation.ZORDER_TOP)
.withString("name","ClearLove")
.withInt("age",12)
.navigation(VideoActivity.this, new NavigationCallback() {
@Override
public void onFound(Postcard postcard) {
Log.e("TAG",postcard.getPath()+","+postcard.getGroup());
}
@Override
public void onLost(Postcard postcard) {
}
@Override
public void onArrival(Postcard postcard) {
}
@Override
public void onInterrupt(Postcard postcard) {
}
});
使用NavigationCallback可以完成對路由的回調,主要分爲4個方面,分別爲onFound(路由尋址成功)、onLost(路由尋址失敗)、onArrival(路由導航成功)、onInterrupt(攔截器),在四個方法中,都涉及到了一個類Postcard
,有兩個比較關鍵的屬性值,分別是path和group,path指的是路由的路徑,group指的是分組。
2020-05-31 17:37:06.335 29646-29646/com.example.glide E/TAG: /app/main_activity,app
默認情況下,group的分組爲app,也就是二級目錄/xx/xxx,第一個位置的數據。
在navigation中除了可以完成路由的回調,還可以完成帶結果的回調,也就是startActivityForResult
,可以傳入requestCode
來實現。
2、ARouter實現服務化
以上只是ARouter使用的一些常用方法,最關鍵的還是在組件化開發中,避免模塊間的強依賴,使用ARouter服務化進行模塊解耦,纔是組件化中的核心。
下面拉回開篇的場景:有兩個ModuleA和ModuleB,ModuleA需要使用ModuleB中的一個類,如果相互依賴組件,本來沒有關係的兩個組件變得耦合性太高;所以對於業務層的抽離,可以在lib_base組件中,創建一個服務接口,該接口可以對外暴露;該接口的具體實現類是在ModuleB中實現的,具體的實現就是ModuleA想要調用ModuleB中的部分方法;那麼當ModuleA想要調用ModuleB中類的方法時,直接依賴lib_base組件,通過ARouter路由獲取,這樣通過lib_base組件將兩個不相干的組件聯繫起來。
當前存在lib_video
lib_base
lib_share
三個組件,lib_share
想要調用lib_video
中的方法,那麼首先在lib_base
中創建一個接口,繼承自IProvider。
public interface VideoService extends IProvider {
String getVideoName();
}
lib_video:
lib_video需要依賴lib_base庫,完成VideoService 的具體實現
@Route(path = "/lib_video/video_service")
public class VideoServiceImpl implements VideoService {
@Override
public String getVideoName() {
Video video = new Video("唐人街探案",3);
return video.getVideoName();
}
@Override
public void init(Context context) {
}
}
lib_share:
lib_share同樣需要依賴lib_base庫,而不需要和lib_video庫依賴。
@Autowired(name = "/lib_video/video_service")
VideoService mVideoService;
private ShareSDKManager(){
ARouter.getInstance().inject(this);
}
private static ShareSDKManager manager;
public static ShareSDKManager getInstance(){
if(manager == null){
synchronized (ShareSDKManager.class){
if(manager == null){
manager = new ShareSDKManager();
}
}
}
return manager;
}
//分享需要2類數據,參數和平臺
public void shareData(ShareData data,PlatformShareDataListener listener){
this.listener = listener;
/*省略部分代碼*/
String videoName = mVideoService.getVideoName();
Log.e("TAG","name=="+videoName);
}
組件路由服務化用法1:聲明服務注意要加上路由地址,否則找不到該實現類,通過服務接口直接調用方法實現。
方法2:通過navigation導航
//不需要再加AutoWried註解
VideoService mVideoService2;
mVideoService2 = ARouter.getInstance().navigation(VideoService.class);
String videoName = mVideoService2.getVideoName();
方法3:通過build導航
//不需要再加AutoWried註解
VideoService mVideoService2;
mVideoService2 = (VideoService) ARouter.getInstance().build("/lib_video/video_service").navigation();
String videoName = mVideoService2.getVideoName();
3、ARouter分組與攔截器
ARouter攔截器,有些類似於之前在OkHttp組件開發中,講到的攔截器。ARouter攔截器主要是攔截事件跳轉,先看下代碼
@Interceptor(priority = 1,name = "login_interceptor")
public class LoginInterceptor implements IInterceptor {
@Override
public void process(Postcard postcard, InterceptorCallback callback) {
if(postcard.getGroup() == Router.NEED_LOGIN){
//如果是需要登錄分組
ARouter.getInstance().build(Router.LOGIN_ACTIVITY).navigation();
}else{
callback.onContinue(postcard);
}
}
@Override
public void init(Context context) {
}
}
這是一個與登錄相關的攔截器,核心在於process,在process方法中有兩個形參,分別是Postcard 和 InterceptorCallback 。
Postcard 在之前介紹過,包含路由地址和分組Group,分組Group是可以在Route註解中聲明的,在路由導航的時候,可以在build中添加分組信息。
@Route(path = Router.MAIN_ACTIVITY,group = Router.NEED_LOGIN)
public class MainActivity extends AppCompatActivity {
ARouter.getInstance()
// 路由地址 分組
.build(Router.MAIN_ACTIVITY,Router.NEED_LOGIN)
當然加了分組之後,就可以通過攔截器,通過Postcard來獲取路由地址的分組,如果獲取到需要分組的信息,那麼就需要判斷登錄信息是否過期(這裏沒有做這個操作,在實際開發中是需要做的),如果沒有過期,那麼就通過InterceptorCallback
執行onContinue
繼續路由到對應地址,如果登錄信息過期,那麼就需要路由到登錄界面。
如果獲取到的分組信息是不需要登錄的,那麼就直接通過InterceptorCallback
執行onContinue
繼續路由到對應地址。