1.路由介紹
什麼是路由框架?
說簡單點就是對映頁面跳轉關係的,當然它也包含跳轉相關的一切功能
為什麼使用ARouter?
我們先從適用場景來分析:
-
動態跳轉:一般來說複雜的電商跳轉多頁面需要很強的靈活性,很多情況下是運營人員動態配置的下發活動頁面,需要靈活的進行跳轉。
-
元件化:隨著業務量的不斷增長,app也會不斷的膨脹,開發團隊的規模和工作量也會逐漸增大,面對所衍生的64K問題、協作開發問題等,app一般都會走向元件化。元件化就是將APP按照一定的功能和業務拆分成多個元件module,不同的元件獨立開發,元件化不僅能夠提供團隊的工作效率,還能夠提高應用效能。而元件化的前提就是解耦,那麼我們首先要做的就是解耦頁面之間的依賴關係
-
Native與H5的問題:現在的APP很少是純Native的,也很少會有純H5的,一般情況下都是將兩者進行結合。這時候就需要非常便捷並且統一的跳轉方案,因為在H5中是無法使用StartActivity()跳轉到Native頁面的,而從Native跳轉到H5頁面也只能通過配置瀏覽器的方式實現
-
其他等場景
原生跳轉方式的不足
顯式跳轉, Intent intent = new Intent(activity, XXActivity.class);
由於需要直接持有對應class,從而導致了強依賴關係,提高了耦合度隱式跳轉,譬如 Intent intent = new Intent(); intent.setAction(“com.android.activity.MY_ACTION”);
action等屬性的定義在Manifest,導致了擴充套件性較差
規則集中式管理,導致協作變得非常困難。原生的路由方案會出現跳轉過程無法控制的問題,因為一旦使用了StartActivity()就無法插手其中任何環節了,只能交給系統管理,這就導致了在跳轉失敗的情況下無法降級,而是會直接丟擲執行時的異常。
2.ARouter的使用
1.新增框架的依賴和配置
在各個模組的build.gradle中新增編譯引數和依賴的框架
android {
defaultConfig {
...
javaCompileOptions {
annotationProcessorOptions {
arguments = [ moduleName : project.getName() ]
}
}
}
}
dependencies {
// 替換成最新版本, 需要注意的是api
// 要與compiler匹配使用,均使用最新版可以保證相容
compile `com.alibaba:arouter-api:1.2.2`
annotationProcessor `com.alibaba:arouter-compiler:1.1.3`
...
}
// 舊版本gradle外掛(< 2.2),可以使用apt外掛,在根build.gradle中配置方法
apply plugin: `com.neenbedankt.android-apt`
buildscript {
repositories {
jcenter()
}
dependencies {
classpath `com.neenbedankt.gradle.plugins:android-apt:1.4`
}
}複製程式碼
2.新增註解
// 在支援路由的頁面上新增註解(必選)
// 這裡的路徑需要注意的是至少需要有兩級,/xx/xx
@Route(path = "/test/activity")
public class YourActivity extend Activity {
...
}複製程式碼
3.初始化SDK
if (isDebug()) { // 這兩行必須寫在init之前,否則這些配置在init過程中將無效
ARouter.openLog(); // 列印日誌
ARouter.openDebug(); // 開啟除錯模式(如果在InstantRun模式下執行,必須開啟除錯模式!線上版本需要關閉,否則有安全風險)
}
ARouter.init(mApplication); // 儘可能早,推薦在Application中初始化複製程式碼
4.路由操作
// 1.普通跳轉
ARouter.getInstance().build("/test/activity").navigation();
// 2.跳轉並攜帶引數
ARouter.getInstance().build("/test/activity2").navigation();
// 3.跳轉並攜帶請求碼
ARouter.getInstance().build("/test/activity2").navigation(this, requestCode);
// 4.URI跳轉
/*這種使用URi的方式中,URi的Scheme 和 host不影響結果,可以隨便設,關鍵的是path
* - build(URI)會把URI解析為path,並把當前URI存入PostCard
* - build(String)構造的PostCard不儲存URI*/
Uri testUriMix = Uri.parse("xx://xxx/test/activity2");
ARouter.getInstance().build(testUriMix)
.withString("name", "老王")
.withInt("age", 18)
.withBoolean("boy", true)
.withLong("high", 180)
.withString("url", "https://a.b.c")
.withParcelable("pac", testParcelable)
.withObject("obj", testObj)
.navigation();
// 5.跳轉包含回撥 單次降級策略可以在這裡使用
ARouter.getInstance().build("/test/activity2").navigation(Context mContext, int requestCode, NavigationCallback callback);複製程式碼
5.配置自定義序列化方式
上訴的程式碼中有withObject進行傳參,沒有定義序列化方式是無法進行解析因此需要定義一個序列化方式,以下采用FastJson進行序列化
// 如果需要傳遞自定義物件,需要實現 SerializationService,並使用@Route註解標註(方便使用者自行選擇序列化方式),例如:
@Route(path = "/service/json")
public class JsonServiceImpl implements SerializationService {
@Override
public void init(Context context) {
}
@Override
public <T> T json2Object(String text, Class<T> clazz) {
return JSON.parseObject(text, clazz);
}
@Override
public String object2Json(Object instance) {
return JSON.toJSONString(instance);
}
}複製程式碼
6.宣告攔截器(攔截跳轉過程,面向切面程式設計)
// 比較經典的應用就是在跳轉過程中處理登陸事件,這樣就不需要在目標頁重複做登陸檢查
// 攔截器會在跳轉之間執行,多個攔截器會按優先順序順序依次執行
@Interceptor(priority = 8, name = "測試用攔截器")
public class TestInterceptor implements IInterceptor {
@Override
public void process(Postcard postcard, InterceptorCallback callback) {
...
callback.onContinue(postcard); // 處理完成,交還控制權
// callback.onInterrupt(new RuntimeException("我覺得有點異常")); // 覺得有問題,中斷路由流程
// 以上兩種至少需要呼叫其中一種,否則不會繼續路由
}
@Override
public void init(Context context) {
// 攔截器的初始化,會在sdk初始化的時候呼叫該方法,僅會呼叫一次
}
}複製程式碼
// 我們經常需要在目標頁面中配置一些屬性,比方說”是否需要登陸”之類的
// 可以通過 Route 註解中的 extras 屬性進行擴充套件,這個屬性是一個 int值,換句話說,單個int有4位元組,也就是32位,可以配置32個開關
// 剩下的可以自行發揮,通過位元組操作可以標識32個開關,通過開關標記目標頁面的一些屬性,在攔截器中可以拿到這個標記進行業務邏輯判斷
@Route(path = “/test/activity”, extras = Consts.XXXX)
7.通過依賴注入解耦:服務管理(一) 暴露服務
// 宣告介面,其他元件通過介面來呼叫服務
public interface HelloService extends IProvider {
String sayHello(String name);
}
// 實現介面
@Route(path = "/service/hello", name = "測試服務")
public class HelloServiceImpl implements HelloService {
@Override
public String sayHello(String name) {
return "hello, " + name;
}
@Override
public void init(Context context) {
}
}複製程式碼
8.通過依賴注入解耦:服務管理(二) 發現服務
public class Test {
@Autowired
HelloService helloService;
@Autowired(name = "/service/hello")
HelloService helloService2;
HelloService helloService3;
HelloService helloService4;
public Test() {
ARouter.getInstance().inject(this);
}
public void testService() {
// 1. (推薦)使用依賴注入的方式發現服務,通過註解標註欄位,即可使用,無需主動獲取
// Autowired註解中標註name之後,將會使用byName的方式注入對應的欄位,不設定name屬性,會預設使用byType的方式發現服務(當同一介面有多個實現的時候,必須使用byName的方式發現服務)
helloService.sayHello("Vergil");
helloService2.sayHello("Vergil");
// 2. 使用依賴查詢的方式發現服務,主動去發現服務並使用,下面兩種方式分別是byName和byType
helloService3 = ARouter.getInstance().navigation(HelloService.class);
helloService4 = (HelloService) ARouter.getInstance().build("/service/hello").navigation();
helloService3.sayHello("Vergil");
helloService4.sayHello("Vergil");
}複製程式碼
小結
官方的文件Github很詳細可以去看看
以上方式可以進行簡單的入門使用了,下一步我們從原始碼分析。