目錄
- 1)依賴和配置
- 2)初始化
- 3)路由操作
- 3.1)跳轉(zhuǎn)并傳參
- 3.2)跳轉(zhuǎn)回調(diào)(startActivityForResult)
- 3.3)通過URL跳轉(zhuǎn)
- 3.4)監(jiān)聽路由過程
- 3.5)分組
- 3.6)fragment路由
- 4)攔截器
- 5)降級策略
- 6)依賴注入服務(wù)(服務(wù)解耦)
- 7)讀源碼
1)依賴和配置
android {
defaultConfig {
...
javaCompileOptions {
annotationProcessorOptions {
arguments = [ moduleName : project.getName() ]
}
}
}
}
dependencies {
// 替換成最新版本, 需要注意的是api
// 要與compiler匹配使用,均使用最新版可以保證兼容
api 'com.alibaba:arouter-api:x.x.x'
annotationProcessor 'com.alibaba:arouter-compiler:x.x.x'
...
}
//混淆規(guī)則
-keep public class com.alibaba.android.arouter.routes.**{*;}
-keep class * implements com.alibaba.android.arouter.facade.template.ISyringe{*;}
# 如果使用了 byType 的方式獲取 Service,需添加下面規(guī)則,保護(hù)接口
-keep interface * implements com.alibaba.android.arouter.facade.template.IProvider
# 如果使用了 單類注入,即不定義接口實(shí)現(xiàn) IProvider,需添加下面規(guī)則,保護(hù)實(shí)現(xiàn)
-keep class * implements com.alibaba.android.arouter.facade.template.IProvider
2)初始化
~/MainApplication.java
if (BuildConfig.DEBUG) { // 這兩行必須寫在init之前,否則這些配置在init過程中將無效
ARouter.openLog(); // 打印日志
ARouter.openDebug(); // 開啟調(diào)試模式(如果在InstantRun模式下運(yùn)行,必須開啟調(diào)試模式!線上版本需要關(guān)閉,否則有安全風(fēng)險(xiǎn))
}
ARouter.init(this); // 盡可能早,推薦在Application中初始化
3)路由操作

3.1)跳轉(zhuǎn)并傳參
應(yīng)用內(nèi)跳轉(zhuǎn)
ARouter.getInstance().build("/test/second").navigation();
//這里的路徑需要注意的是至少需要有兩級,/xx/xx
@Route(path = "/test/second")
public class SecondActivity extends AppCompatActivity {
...
}
跳轉(zhuǎn)并傳參
| 參數(shù)類型 | 基本類型 |
|---|---|
| .withString( String key, String value ) | |
| .withBoolean( String key, boolean value) | |
| .withChar( String key, char value ) | |
| .withShort( String key, short value) | |
| .withInt( String key, int value) | |
| .withLong( String key, long value) | |
| .withDouble( String key, double value) | |
| .withByte( String key, byte value) | |
| .withFloat( String key, float value) | |
| .withCharSequence( String key, CharSequence value) |
| 參數(shù)類型 | 數(shù)組類型 |
|---|---|
| .withParcelableArray(String key, Parcelable[] value) | |
| .withParcelableArrayList( String key, ArrayList<? extends Parcelable > value) | |
| .withSparseParcelableArray(String key, SparseArray<? extends Parcelable> value) | |
| .withStringArrayList( String key, ArrayList<String> value) | |
| .withIntegerArrayList( String key, ArrayList<Integer> value) | |
| .withCharSequenceArrayList( String key, ArrayList<CharSequence> value) | |
| . withByteArray(String key, byte[] value) | |
| .withShortArray( String key, short[] value) | |
| .withCharArray( String key, char[] value) | |
| .withFloatArray( String key, float[] value) | |
| .withCharSequenceArray( String key, CharSequence[] value) |
| 參數(shù)類型 | 其他類型 |
|---|---|
| .with( Bundle value ) | |
| .withBundle(String key, Bundle value ) | |
| .withObject(String key, Object value ) | |
| .withParcelable(String key,Parcelable value) | |
| .withSerializable(String key, Serializable value) |
ARouter.getInstance()
.build("/test/second")
.withString("key1","我是傳遞的String參數(shù)")
.withObject("key2",new UserBean("我是對象的name參數(shù)","我是對象的age參數(shù)"))
.withParcelable("key3",new TestParcelable("我是Parcelable的name",1))
.navigation();

@Route(path = "/test/second")
public class SecondActivity extends AppCompatActivity {
@Autowired
//或自定義名稱 @Autowired(name = "xxx")
public String key1;
@Autowired
public UserBean key2;
@Autowired
public TestParcelable key3;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_second);
//inject來注入@Autowired注解的字段
ARouter.getInstance().inject(this);
TextView txt = findViewById(R.id.txt);
txt.setText("key1= "+key1+" , key2= "+(key2!=null?key2.getName():"未獲取值")+" , key3= "+(key3!=null?key3.getName():"未獲取值"));
}
}
針對自定義對象的傳遞,
-可以采用withParcelable,在目標(biāo)Activity中直接通過注入的方式獲取對象即可。
-還有一種方式是withObject,對于withObject,ARouter會(huì)將其轉(zhuǎn)換為json字符串,所以在目標(biāo)Activity中獲取的時(shí)候,可以通過 @Autowired public UserBean key2;注解來注入直接使用,但是前提是實(shí)現(xiàn)ARouter的SerializationService接口!!!。
-關(guān)于自定義服務(wù)將在 -6)依賴注入服務(wù)(服務(wù)解耦)中說明
ARouter定義了一個(gè)服務(wù)接口SerializationService.java

我們可以定義一個(gè)自定義服務(wù)實(shí)現(xiàn)此接口
@Route(path = "/service/json")
//因?yàn)閷?shí)現(xiàn)了ARouter的SerializationService接口,我們自定義的對象即可不用寫代碼序列化而直接使用
public class JsonServiceImpl implements SerializationService {
@Override
public <T> T json2Object(String input, Class<T> clazz) {
return null;
}
@Override
public String object2Json(Object instance) {
return JSON.toJSONString(instance);
}
@Override
public <T> T parseObject(String input, Type clazz) {
return JSON.parseObject(input,clazz);
}
@Override
public void init(Context context) {
}
}
這樣即可在目標(biāo)Activity即可使用注解的方式注入一個(gè)普通對象
@Autowired
public UserBean key2;
3.2)跳轉(zhuǎn)回調(diào)(startActivityForResult)
可以使用如下方法
navigation(Activity mContext, int requestCode)
ARouter.getInstance()
.build("/com/second")
.navigation( this , 100 );
@Override
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
super.onActivityResult(requestCode, resultCode, data);
switch (requestCode){
case 100:
if (resultCode == RESULT_OK){
Toast.makeText(this,"收到onActivityResult",Toast.LENGTH_SHORT).show();
}
break;
}
}
3.3)通過URL跳轉(zhuǎn)

// 新建一個(gè)Activity用于監(jiān)聽Schame事件,之后直接把url傳遞給ARouter即可
public class SchameFilterActivity extends Activity {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
Uri uri = getIntent().getData();
ARouter.getInstance().build(uri).navigation();
finish();
}
}
~/AndroidManifest.xml
<activity android:name=".filter.SchameFilterActivity">
<intent-filter>
<data
android:host="app"
android:scheme="jsksy" />
<action android:name="android.intent.action.VIEW" />
<category android:name="android.intent.category.DEFAULT" />
<category android:name="android.intent.category.BROWSABLE" />
</intent-filter>
</activity>
~/調(diào)試用html
注意URL中傳遞的JSON數(shù)據(jù)要轉(zhuǎn)碼
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title></title>
</head>
<body>
<br/>
<!-- <a href="[scheme]://[host]/[path]?[query]">啟動(dòng)應(yīng)用程序</a> -->
<a href="jsksy://app/test/second?key1=tgf&key2=%7b%22name%22%3a%22我是對象的name參數(shù)%22%2c%22age%22%3a%22我是對象的age參數(shù)%22%7d">jsksy://app/test/second?key1=tgf&key2={"name":"我是對象的name參數(shù)","age":"我是對象的age參數(shù)"}</a><br/>
<!-- <a href="jsksy://app/GK_Home/tgf/16">tgftgf</a><br/> -->
<a id="url_addr" href="">jszk://app//view/point/pointsearch</a><br/>
<script type="text/javascript">
/*
* 智能機(jī)瀏覽器版本信息:
*/
var browser={
versions:function(){
var u = navigator.userAgent, app = navigator.appVersion;
return {//移動(dòng)終端瀏覽器版本信息
trident: u.indexOf('Trident') > -1, //IE內(nèi)核
presto: u.indexOf('Presto') > -1, //opera內(nèi)核
webKit: u.indexOf('AppleWebKit') > -1, //蘋果、谷歌內(nèi)核
gecko: u.indexOf('Gecko') > -1 && u.indexOf('KHTML') == -1, //火狐內(nèi)核
mobile: !!u.match(/AppleWebKit.*Mobile.*/)||!!u.match(/AppleWebKit/), //是否為移動(dòng)終端
ios: !!u.match(/\(i[^;]+;( U;)? CPU.+Mac OS X/), //ios終端
android: u.indexOf('Android') > -1 || u.indexOf('Linux') > -1, //android終端或者uc瀏覽器
iPhone: u.indexOf('iPhone') > -1 || u.indexOf('Mac') > -1, //是否為iPhone或者QQ HD瀏覽器
iPad: u.indexOf('iPad') > -1, //是否iPad
webApp: u.indexOf('Safari') == -1 //是否web應(yīng)該程序,沒有頭部與底部
};
}(),
language:(navigator.browserLanguage || navigator.language).toLowerCase()
}
if (browser.versions.mobile && browser.versions.android) {
document.getElementById('url_addr').href = "jszk://app/view/school/schooldetail?uCode=1101";
}else if(browser.versions.mobile && browser.versions.ios){
document.getElementById('url_addr').href = "jszk://app/view/school/schooldetail/:1101";
}
document.writeln("語言版本: "+browser.language);
document.writeln(" 是否為移動(dòng)終端: "+browser.versions.mobile);
document.writeln(" ios終端: "+browser.versions.ios);
document.writeln(" android終端: "+browser.versions.android);
document.writeln(" 是否為iPhone: "+browser.versions.iPhone);
document.writeln(" 是否iPad: "+browser.versions.iPad);
document.writeln(navigator.userAgent);
</script>
</html>
- URL中不能傳遞Parcelable類型數(shù)據(jù),JSON可以通過ARouter api傳遞Parcelable對象
@Autowired
public UserBean key2; //可以接收URL中的json!
@Autowired
public TestParcelable key3; //不可以接收URL中的json!
3.4)監(jiān)聽路由過程
ARouter.getInstance()
.build("/test/second")
.withString("key1","我是傳遞的String參數(shù)")
.withObject("key2",new UserBean("我是對象的name參數(shù)","我是對象的age參數(shù)"))
.withParcelable("key3",new TestParcelable("我是Parcelable的name",1))
.navigation(this, new NavCallback() {
@Override
public void onFound(Postcard postcard) {
Logger.d("路由被目標(biāo)發(fā)現(xiàn)");
super.onFound(postcard);
}
@Override
public void onInterrupt(Postcard postcard) {
Logger.d("路由被攔截");
super.onInterrupt(postcard);
}
@Override
public void onArrival(Postcard postcard) {
Logger.d("路由到達(dá)");
}
@Override
public void onLost(Postcard postcard) {
Logger.d("路由丟失");
super.onLost(postcard);
}
});
3.5)分組
- SDK中針對所有的路徑(/test/1 /test/2)進(jìn)行分組,分組只有在分組中的某一個(gè)路徑第一次被訪問的時(shí)候,該分組才會(huì)被初始化。所以使用分組來管理,ARouter在初始化的時(shí)候只會(huì)一次性地加載所有的root結(jié)點(diǎn),而不會(huì)加載任何一個(gè)Group結(jié)點(diǎn),然后在第一次需要加載組內(nèi)的某個(gè)頁面時(shí)再將test這個(gè)組加載進(jìn)來
- 可以通過 @Route 的group注解主動(dòng)指定分組,否則使用路徑中第一段字符串(/*/)作為分組
@Route(path = "/test/second" ,group = "test")
public class SecondActivity extends AppCompatActivity {
}
- 注意:一旦主動(dòng)指定分組之后,應(yīng)用內(nèi)路由需要使用 ARouter.getInstance().build(path, group) 進(jìn)行跳轉(zhuǎn),手動(dòng)指定分組,否則無法找到
ARouter.getInstance().build("test/second", "test")
-
但是最新api手動(dòng)指定分組已經(jīng)過時(shí)語法
手動(dòng)指定分組已經(jīng)過時(shí)語法
3.6)fragment路由
- 創(chuàng)建fragment
@Route(path = "/test/fragment")
public class TestFragment extends Fragment {
@Nullable
@Override
public View onCreateView(@NonNull LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) {
View view = inflater.inflate(R.layout.fragment_test,container,false);
return view;
}
}
- 調(diào)用
Fragment fragment = (Fragment) ARouter.getInstance().build( "/test/fragment" ).navigation();
FragmentManager fm = getSupportFragmentManager();
FragmentTransaction ft = fm.beginTransaction();
ft.add(R.id.frame_layout,fragment);
ft.commit();
4)攔截器
@Interceptor(priority = 1, name = "測試用攔截器")
public class TestInterceptor implements IInterceptor {
@Override
public void process(Postcard postcard, InterceptorCallback callback) {
Logger.d(postcard.getPath()); //打印:/test/second
Logger.d(postcard.getGroup()); //打印:test
Logger.d(postcard.getExtra()); //打?。?
Logger.d(postcard.getExtras()); //打?。築undle[{key1=我是傳遞的String參數(shù), key2={"age":"我是對象的age參數(shù)","name":"我是對象的name參數(shù)"}, key3=com.tgf.studyarouter.bean.TestParcelable@52254f}]
// if ("/test/second".equals(postcard.getPath())) //可以對單個(gè)路由使用
//也可以使用extras 屬性進(jìn)行標(biāo)識(shí)
if (postcard.getExtra() == 1){
callback.onInterrupt(null);
ARouter.getInstance()
.build("/test/login")
.navigation();
}else
{
callback.onContinue(postcard); // 處理完成,交還控制權(quán)
}
// callback.onContinue(postcard); // 處理完成,交還控制權(quán)
// callback.onInterrupt(new RuntimeException("我覺得有點(diǎn)異常")); // 覺得有問題,中斷路由流程
// **以上兩種至少需要調(diào)用其中一種,否則不會(huì)繼續(xù)路由**
}
@Override
public void init(Context context) {
// 攔截器的初始化,會(huì)在sdk初始化的時(shí)候調(diào)用該方法,僅會(huì)調(diào)用一次
}
}

// 我們經(jīng)常需要在目標(biāo)頁面中配置一些屬性,比方說"是否需要登陸"之類的
// 可以通過 Route 注解中的 extras 屬性進(jìn)行擴(kuò)展,這個(gè)屬性是一個(gè) int值,換句話說,單個(gè)int有4字節(jié),也就是32位,可以配置32個(gè)開關(guān)
// 剩下的可以自行發(fā)揮,通過字節(jié)操作可以標(biāo)識(shí)32個(gè)開關(guān),通過開關(guān)標(biāo)記目標(biāo)頁面的一些屬性,在攔截器中可以拿到這個(gè)標(biāo)記進(jìn)行業(yè)務(wù)邏輯判斷
@Route(path = "/test/second" ,extras = 1)
public class SecondActivity extends AppCompatActivity {
...
}

- 可使用綠色通道(跳過所有的攔截器) greenChannel()
ARouter.getInstance()
.build("/test/second")
.greenChannel()
.navigation();
5)降級策略
ARouter定義了服務(wù)接口DegradeService.java,能讓我們在route lost的時(shí)候,做點(diǎn)事兒。

我們自定義一個(gè)接口去實(shí)現(xiàn)DegradeService,當(dāng)route丟失的時(shí)候,我們讓路由進(jìn)入首頁。
// 自定義全局降級策略
// 實(shí)現(xiàn)DegradeService接口,并加上一個(gè)Path內(nèi)容任意的注解即可
// 注意不要在 navigationnew NavCallback()
@Route(path = "/service/degrade")
public class DegradeServiceImpl implements DegradeService {
@Override
public void onLost(Context context, Postcard postcard) {
//路由進(jìn)入首頁
ARouter.getInstance()
.build("/test/first")
.navigation();
}
@Override
public void init(Context context) {
Logger.d("DegradeServiceImpl - init");
}
}
6)依賴注入服務(wù)(服務(wù)解耦)
可以通過依賴注入解耦服務(wù),有點(diǎn)類似mvp中的model,可通過此方式將所有服務(wù)按類別抽離。
-暴露服務(wù)
//聲明接口,繼承IProvider,其他組件通過接口來調(diào)用服務(wù)
public interface HelloService extends IProvider {
void sayHello(String str);
}
// 實(shí)現(xiàn)接口
@Route(path = "/service/hello", name = "測試服務(wù)")
public class HelloServiceImpl implements HelloService {
private Context mContext;
@Override
public void sayHello(String str) {
Toast.makeText(mContext,"hello"+str,Toast.LENGTH_SHORT).show();
}
@Override
public void init(Context context) {
mContext = context;
}
}
-發(fā)現(xiàn)服務(wù)
@Route(path = "/test/login")
public class LoginActivity extends AppCompatActivity {
@Autowired(name = "/service/hello")
HelloService helloService;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_login);
//第1種方式(推薦): 通過@Autowired依賴注入的方式發(fā)現(xiàn)服務(wù),通過注解標(biāo)注字段,即可使用,無需主動(dòng)獲取
//Autowired注解中標(biāo)注name之后,將會(huì)使用byName的方式注入對應(yīng)的字段,不設(shè)置name屬性,會(huì)默認(rèn)使用byType的方式發(fā)現(xiàn)服務(wù)(當(dāng)同一接口有多個(gè)實(shí)現(xiàn)的時(shí)候,必須使用byName的方式發(fā)現(xiàn)服務(wù))
ARouter.getInstance().inject(this);
findViewById(R.id.btn).setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
//第2種方式 :通過依賴查找的方式 ,可不用inject 和 Autowired
// ((HelloService)ARouter.getInstance().build("/service/hello")
// .navigation())
// .sayHello("涂高峰");
//第3種方式 :通過依賴查找的方式,可不用inject 和 Autowired
// ARouter.getInstance().navigation(HelloService.class).sayHello("涂高峰");
helloService.sayHello("涂高峰");
}
});
}
}
7)讀源碼
未完待續(xù)...
