Android路由框架Router
什么是路由?說簡單點就是映射頁面跳轉(zhuǎn)關(guān)系的哑舒,當然它也包含跳轉(zhuǎn)相關(guān)的一切功能琼稻。
路由框架的意義
Android系統(tǒng)已經(jīng)給我們提供了api來做頁面跳轉(zhuǎn),比如startActivity
提鸟,為什么還需要路由框架呢?我們來簡單分析下路由框架存在的意義:
- 在一些復雜的業(yè)務(wù)場景下仅淑,靈活性比較強称勋,很多功能都是動態(tài)配置的,比如下發(fā)一個活動頁面涯竟,我們事先并不知道具體的目標頁面赡鲜,但如果事先做了約定空厌,提前做好頁面映射,便可以自由配置银酬。
- 隨著業(yè)務(wù)量的增長嘲更,客戶端必然隨之膨脹,開發(fā)人員的工作量越來越大揩瞪,比如64K問題赋朦,比如協(xié)作開發(fā)問題。App一般都會走向組件化的道路李破,而組件化的前提就是解耦宠哄,那么我們首先要做的就是解耦頁面之間的依賴關(guān)系。
- 簡化代碼嗤攻。數(shù)行跳轉(zhuǎn)代碼精簡成一行代碼琳拨。
- 其他...
特性
Router
有哪些特性或者優(yōu)點呢?
- 基于注解屯曹,使用方便狱庇,源碼簡潔
- 鏈式調(diào)用,api友好
- 多路徑支持
- 結(jié)果回調(diào)恶耽,每次跳轉(zhuǎn)都會回調(diào)跳轉(zhuǎn)結(jié)果
- 編譯期處理注解密任,不影響運行時性能
- 除了可以使用注解定義路由,還支持手動分配路由
- 自定義攔截器偷俭,可以對路由進行攔截浪讳,比如登錄判斷和埋點處理
- 自定義路由匹配規(guī)則,相比較其他路由框架涌萤,該項目并沒有限制路由的寫法淹遵,除了內(nèi)置的幾個匹配器,用戶完全可以定義自己的規(guī)則
- 支持隱式Intent跳轉(zhuǎn)
- 支持多模塊使用负溪,支持組件化開發(fā)
- 不僅支持注解Activity透揣,還支持注解Fragment
- 支持Kotlin
其他功能正在添加中...
集成
router-gradle-plugin |
router |
router-compiler |
|
---|---|---|---|
最新版本 | [站外圖片上傳中……(3)] |
集成過程也可參考項目主頁README。
- 在項目級的
build.gradle
中加入依賴:
buildscript {
repositories {
jcenter()
}
dependencies {
classpath 'com.android.tools.build:gradle:2.2.x ↑'
classpath 'com.chenenyu.router:gradle-plugin:latest.integration'
}
}
注意川抡,Router
需要使用2.2.0
及以上版本的Android gradle plugin
來處理注解辐真,截至寫作時,最新版本為2.3.3
崖堤。
- 在module級的
build.gradle
中使用plugin:
apply plugin: 'com.android.application/library'
apply plugin: 'com.chenenyu.router'
至此侍咱,集成工作就完成了,簡單的兩步:添加插件路徑和應(yīng)用插件密幔。這應(yīng)該是類似框架中最簡單的集成方式了楔脯。
使用
-
Router
需要初始化,用于初始化路由表胯甩,建議放到Application
中做:
public class App extends MultiDexApplication {
@Override
public void onCreate() {
super.onCreate();
// 開啟log昧廷,要放到前面才能看到初始化過程的log
if (BuildConfig.DEBUG) {
Router.openLog();
}
// 初始化
Router.initialize(this);
}
}
- 添加路由注解
// 單路徑注解
@Route("test")
public class TestActivity extends Activity {
...
}
// 多路徑注解堪嫂,這幾個注解都能打開該Activity
@Route({"user", "example://user", "http://example.com/user"})
public class UserActivity extends Activity {
...
}
@Route("fragment")
public class TestFragment extends Fragment {
...
}
- 發(fā)起路由操作
// 最簡單的路由跳轉(zhuǎn),打開TestActivity
Router.build("test").go(context);
// 其他部分api
Router.build("test")
.requestCode(int) // 調(diào)用startActivityForResult
.with(bundle) // 攜帶跳轉(zhuǎn)參數(shù)
.addFlags(flag) // 添加標記麸粮,比如intent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP)
.anim(enter, exit) // 添加跳轉(zhuǎn)動畫
.callback(calback) // 跳轉(zhuǎn)結(jié)果回調(diào)
.go(this);
全部可用API可參考IRouter
接口溉苛。
- startActivityForResult
Router.build(uri).requestCode(int).go(this);
其中requestCode
一定得是一個非負數(shù)镜廉。
go()
有如上幾個重載方法弄诲,如果是在Fragment中發(fā)起startActivityForResult
路由操作,切記傳當前fragment實例哦娇唯!不然在fragment中是接受不到回調(diào)的齐遵。
- 添加跳轉(zhuǎn)動畫
// 1. 基礎(chǔ)動畫
Router.build(uri).anim(enter, exit).go(this);
// 2. 轉(zhuǎn)場動畫ActivityOptions
Router.build(uri).activityOptions(options).go(this);
- 獲取目標頁面
// 1. 獲取intent,然后可以操作intent
Intent intent = Router.build(uri).getIntent(context);
// 2. 獲取fragment塔插,然后可以將該fragment添加到Activity中
Fragment fragment = (Fragment) Router.build(uri).getFragment(context);
- 全局攔截器
// 1. 添加全局攔截器
Router.addGlobalInterceptor(routeInterceptor);
// 2. 跳過全局攔截器
Router.build(uri).skipInterceptors().go(this);
- 添加攔截器
攔截器是Router
的功能之一梗摇,作用就是在執(zhí)行路由之前判斷是否需要攔截該次路由請求。比如可以在攔截器中做登錄狀態(tài)判斷想许。
// 定義攔截器(通過注解)
@Interceptor("SampleInterceptor")
public class SampleInterceptor implements RouteInterceptor {
@Override
public boolean intercept(Context context, @NonNull Uri uri, @Nullable Bundle extras) {
// 返回true表示攔截當前路由
return true;
}
}
// 定義攔截器(通過代碼)
Router.handleInterceptorTable(new InterceptorTable() {
@Override
public void handle(Map<String, Class<? extends RouteInterceptor>> map) {
map.put("SampleInterceptor", SampleInterceptor.class);
}
});
// 應(yīng)用攔截器(通過注解)
@Route(value = "test", interceptors = "SampleInterceptor")
public class TestActivity extends AppCompatActivity {
...
}
// 應(yīng)用攔截器(通過代碼)
Router.handleTargetInterceptors(new TargetInterceptors() {
@Override
public void handle(Map<Class<?>, String[]> map) {
map.put(TestActivity.class, new String[]{"SampleInterceptor"});
}
});
- 自定義路由
除了可以使用注解來添加路由外(上面步驟2介紹的方式)伶授,還可以通過代碼手動控制路由表。
// 動態(tài)添加路由表
Router.handleRouteTable(new RouteTable() {
@Override
public void handle(Map<String, Class<?>> map) {
map.put("dynamic1", TestActivity.class);
map.put("dynamic2", TestFragment.class);
...
}
});
該方式與注解沒有沖突流纹,可以同時使用糜烹。
- 路由匹配規(guī)則
該功能是Router
最大的特色功能,不同于其他框架漱凝,Router
并沒有規(guī)定路由的寫法規(guī)則疮蹦,而是抽象出Matcher
的概念,交給用戶去控制茸炒。但是Router
仍然內(nèi)置了4個常用的Matcher
愕乎。
匹配優(yōu)先級從高到低依次是
DirectMatcher
、SchemeMatcher
壁公、ImplicitMatcher
和BrowserMatcher
感论,關(guān)于原理將在后序的原理篇中進行講解。假設(shè)有如下路由頁面:
@Route({"user", "http://example.com/user"})
public class UserActivity extends Activity {
...
}
除了可以通過Router.build("test").go(this)
和Router.build("http://example.com/user").go(this)
打開UserActivity之外(DirectMatcher
命中)紊册,還可以通過Router.build("http://example.com/user?id=9527&status=0").go(this)
打開(通過SchemeMatcher
命中)笛粘,并且自動幫你配置了Bundle參數(shù),即:
@Route({"user", "http://example.com/user"})
public class UserActivity extends Activity {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_test);
Bundle bundle = getIntent().getExtras();
String id = bundle.getString("id");
String status = bundle.getString("status");
}
}
Matcher
支持配置多個湿硝,會根據(jù)優(yōu)先級依次進行匹配薪前。
- 參數(shù)注入
上面講了可以通過路由傳遞參數(shù),然后在目標頁面通過Bundle獲取关斜,其實這個過程也被Router
簡化了示括。通過@InjectParam
注解可以為Activity或者Fragment的成員變量添加參數(shù)注入
@Route({"test", "http://example.com/test", "router://test"})
public class TestActivity extends AppCompatActivity {
@InjectParam
int id = 123;
@InjectParam(key = "status")
private String sts = "default"; // 不建議使用private修飾符
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_test);
Router.injectParams(this); // 實現(xiàn)參數(shù)注入
}
}
-
@InjectParam
會在Bundle中取出對應(yīng)key的值傳給成員變量,默認key為變量名痢畜,也可以通過key=""屬性指定 - 參數(shù)注入支持變量的默認值垛膝,目前支持默認值的變量類型有基本數(shù)據(jù)類型鳍侣,String,CharSequence吼拥,其他類型的默認值都是null
- 變量不建議使用
private
修飾符倚聚,因為私有的變量會采用反射的方式注入?yún)?shù) - 需要使用
Router.injectParams(this)
來實現(xiàn)最終的參數(shù)注入
Router
還有其他一些人性化的小功能,在這里就不一一介紹了凿可,有問題可以在項目主頁提issue惑折。后續(xù)會給大家講解一下背后的實現(xiàn)原理。
總結(jié)
Router
是一個十分小巧靈活的路由框架枯跑,代碼設(shè)計也很優(yōu)雅簡潔惨驶,且完美支持組件化開發(fā),目前仍在不斷地迭代中敛助,源碼地址為https://github.com/chenenyu/Router粗卜,歡迎各位試用點評。