Android 路由框架

不怕跌倒鳖链,所以飛翔

參考文獻(xiàn):
superxlcr的ARouter學(xué)習(xí)筆記
碼字農(nóng)民工的文章
繁華落盡666的文章

本文主要介紹的知識(shí)點(diǎn)

  • 關(guān)于android路由框架解決的問(wèn)題
  • android路由框架的使用(這里只是介紹ARouter的使用)
  • 關(guān)于使用ARouter框架的注意事項(xiàng)
  • 總結(jié)

1.Android路由框架解決的問(wèn)題

相信大家在工作中都會(huì)遇到這樣的問(wèn)題,通過(guò)其他App或者通過(guò)網(wǎng)頁(yè)跳轉(zhuǎn)到指定的自己的App或者跳轉(zhuǎn)到指定的頁(yè)面中去,一般都是在推送中或者通過(guò)Banner點(diǎn)擊之后的操作,一般的操作都是像下面這樣的

  • 設(shè)置相應(yīng)的intent-filter
<intent-filter>
    <action android:name="com.hejin.arouter.Main2Activity"/>
    <category android:name="android.intent.category.DEFAULT"/>
</intent-filter>
  • 通過(guò)Intent隱式跳轉(zhuǎn)到相應(yīng)的Activity
    Intent intent = new Intent();
    intent.setAction("com.hejin.arouter.Main2Activity");
    startActivity(intent);

其實(shí)這里我要說(shuō)明一下,如果你是正規(guī)的開(kāi)發(fā)公司我覺(jué)得一般都不會(huì)這么去寫(xiě),其實(shí)這個(gè)跳轉(zhuǎn)完全能實(shí)現(xiàn),但是一般正規(guī)的公司都會(huì)定一些協(xié)議和端口號(hào),也就是說(shuō)會(huì)添加scheme來(lái)指定一些數(shù)據(jù)的協(xié)議部分和path進(jìn)行匹配,但是隨著時(shí)間的推移和團(tuán)隊(duì)的擴(kuò)大,會(huì)慢慢的暴露出很多問(wèn)題:

  • 集中式的URL管理:談到集中式的管理,總是比較蛋疼柠硕,多人協(xié)同開(kāi)發(fā)的時(shí)候,大家都去AndroidManifest.xml中定義各種IntentFilter瞧甩,使用隱式Intent,最終發(fā)現(xiàn)AndroidManifest.xml中充斥著各種Schame融蹂,各種Path悍赢,需要經(jīng)常解決Path重疊覆蓋、過(guò)多的Activity被導(dǎo)出戏挡,引發(fā)安全風(fēng)險(xiǎn)等問(wèn)題
  • 可配置性較差:Manifest限制于xml格式芍瑞,書(shū)寫(xiě)麻煩,配置復(fù)雜褐墅,可以自定義的東西也較少
  • 跨模塊無(wú)法顯式依賴:在App小有規(guī)模的時(shí)候拆檬,我們會(huì)對(duì)App做水平拆分,按照業(yè)務(wù)拆分成多個(gè)子模塊妥凳,之間完全解耦竟贯,通過(guò)打包流程控制App功能,這樣方便應(yīng)對(duì)大團(tuán)隊(duì)多人協(xié)作逝钥,互相邏輯不干擾屑那,這時(shí)候只能依賴隱式Intent跳轉(zhuǎn),書(shū)寫(xiě)麻煩艘款,成功與否難以控制持际。

尤其是在項(xiàng)目演進(jìn)的時(shí)候都會(huì)進(jìn)行組件化開(kāi)發(fā),所以這里網(wǎng)上有很多大神就研究出路由框架這么一個(gè)東西,解決了上面的相應(yīng)問(wèn)題,這里接觸的就是阿里巴巴開(kāi)源的ARouter在GitHub上已經(jīng)已經(jīng)有3.+k的start了,相對(duì)來(lái)說(shuō)應(yīng)該比較穩(wěn)定,所以讓我們開(kāi)始吧!

2.ARouter的簡(jiǎn)單使用

2.1首先是把ARouter引入到項(xiàng)目中去

  • 首先在在module中配置相應(yīng)的參數(shù)
    defaultConfig {
        .......
        javaCompileOptions {
            annotationProcessorOptions {
                arguments = [ moduleName : project.getName() ]
            }
        }
    }
  • 然后配置api和compiler(這個(gè)也是在module中)
dependencies {
    compile 'com.alibaba:arouter-api:x.x.x'
    annotationProcessor 'com.alibaba:arouter-compiler:x.x.x'
    ...
}
  • 上面是github上面寫(xiě)的內(nèi)容,但是有一點(diǎn)他沒(méi)有寫(xiě),但是就是一定要在項(xiàng)目的gradle中添加下面這段代碼:
    dependencies {
        classpath 'com.android.tools.build:gradle:2.3.3'
        classpath 'com.neenbedankt.gradle.plugins:android-apt:1.8' //路由需要
        // NOTE: Do not place your application dependencies here; they belong
        // in the individual module build.gradle files
    }

這句話一定要加上否則根本就跳轉(zhuǎn)不過(guò)去,具體為什么我還真是不知道....
有了以上的內(nèi)容就完成了基本的配置,就可以進(jìn)行相應(yīng)的跳轉(zhuǎn)了...

2.2代碼中的簡(jiǎn)單使用

  • 在Application中初始化ARouter
        /*初始化路由框架*/
        ARouter.init(this);
  • 首先要在你要跳轉(zhuǎn)的Activity(或者說(shuō)是目標(biāo)的Activity)添加注釋
@Route(path = "XXX/XXX")

這里面要注意兩點(diǎn)首先這個(gè)注解里面的內(nèi)容必須是二級(jí)菜單,這個(gè)在github上面有解釋,其次就是這個(gè)注解要寫(xiě)在Activity的類上邊

  • 通過(guò)代碼進(jìn)行跳轉(zhuǎn)(發(fā)起路由)
ARouter.getInstance().build("/XXX/XXX").navigation();
//跳轉(zhuǎn)中攜帶參數(shù)
ARouter.getInstance().build("/XXX/XXX")
             .withLong("key", "value")
             .withString("key", "value")
             .navigation

這里面的參數(shù)要和你要跳轉(zhuǎn)的Activity注解中的參數(shù)保持一致,當(dāng)你傳遞參數(shù)的時(shí)候,你直接通過(guò)Intent去取就可以了.

通過(guò)以上步驟就能實(shí)現(xiàn)基本的跳轉(zhuǎn)傳遞參數(shù)了,但是身為有逼格的程序員我們?cè)趺茨苓@樣就滿足了呢?

3.ARouter進(jìn)階使用

3.1 利用Uri進(jìn)行跳轉(zhuǎn)

        Uri uri = Uri.parse("/test/activity");
        ARouter.getInstance()
                .build(uri)
                .navigation();

3.2傳遞參數(shù)的獲取問(wèn)題

當(dāng)你傳遞參數(shù)的時(shí)候你可以通過(guò)Intent取獲取,當(dāng)然也可以通過(guò)相應(yīng)的注解進(jìn)行獲取,就像下面這樣:

@Autowired(name = "xxx")
public String text;

這里呢要注意,修飾符必須是public并且key值要相互對(duì)應(yīng).還要在目標(biāo)的Activtiy中添加ARouter.getInstance().inject(this);才可以使用相應(yīng)的值,否則取值的時(shí)候會(huì)失敗,但是不會(huì)報(bào)空指針.

3.3關(guān)于轉(zhuǎn)場(chǎng)動(dòng)畫(huà)的跳轉(zhuǎn)處理

有沒(méi)有想過(guò),之前在Activity跳轉(zhuǎn)的時(shí)候可以使用overridePendingTransition();,但是現(xiàn)在通過(guò)路由跳轉(zhuǎn)的話,沒(méi)有地方取設(shè)置動(dòng)畫(huà)了,然后ARouter為我們想到了這個(gè)問(wèn)題.

  • 舊動(dòng)畫(huà):使用withTransition方法即可(相當(dāng)于之前的overridePendingTransition()方法設(shè)置)
ARouter.getInstance().build(path).withTransition(R.anim_slide_in,R.anim_slide_out);
  • 新動(dòng)畫(huà):使用withOptionsCompat方法即可(Android5.0新出的轉(zhuǎn)場(chǎng)動(dòng)畫(huà))
ActivityOptionsCompat compat = ActivityOptionsCompat.  
                makeScaleUpAnimation(view, view.getWidth() / 2, view.getHeight() / 2, 0, 0);  
  
ARouter.getInstance().build("path").withOptionsCompat(compat)  
                .navigation();  

3.4ARouter處理跳轉(zhuǎn)過(guò)程的結(jié)果

ARouter可以讓我們處理跳轉(zhuǎn)過(guò)程的結(jié)果,什么用呢?就是你找到目標(biāo)之后要進(jìn)行什么操作.

ARouter.getInstance().build("/module/jumpTestActivity2").navigation(null,  
        new NavigationCallback() {  
            @Override  
            public void onFound(Postcard postcard) {  
                // 找到目標(biāo)后進(jìn)行的操作  
            }  
  
            @Override  
            public void onLost(Postcard postcard) {  
                // 找不到目標(biāo)進(jìn)行的操作  
            }  
        });  

補(bǔ)充說(shuō)明:
在最新api中已經(jīng)是四個(gè)方法了!

        ARouter.getInstance().build("/test/activity").navigation(this, new NavigationCallback() {
            @Override
            public void onFound(Postcard postcard) {
        //找到隊(duì)?wèi)?yīng)的內(nèi)容的時(shí)候
                Log.e("done", "onFound: ");
            }

            @Override
            public void onLost(Postcard postcard) {
        //沒(méi)有找到對(duì)應(yīng)的內(nèi)容的時(shí)候
                Log.e("done", "onLost: ");
            }

            @Override
            public void onArrival(Postcard postcard) {
        //跳轉(zhuǎn)成功
                Log.e("done", "onArrival: ");
            }

            @Override
            public void onInterrupt(Postcard postcard) {
        //攔截操作
                Log.e("done", "onInterrupt: ");
            }
        });

這里可以在onLost中去處理"位置頁(yè)面"的跳轉(zhuǎn)結(jié)果,比如升級(jí)APP之類的話術(shù).

3.5攜帶結(jié)果的Activity

ARouter.getInstance().build("/test/activity").navigation(this,10);

后面那個(gè)參數(shù)就是請(qǐng)求碼,別的和之前的都一樣.

3.6組的概念

在ARouter中有個(gè)組的概念,什么意思呢?就是在構(gòu)建路由請(qǐng)求的時(shí)候,可以指定分組.
其實(shí)這個(gè)分組本來(lái)就是有個(gè)你像path=/test/activity test就相當(dāng)是分組,但是也可以使用group進(jìn)行分組,像下面這段代碼:

@Route(path = "/test/activity", group = "app")

這里需要強(qiáng)調(diào)一下,如果你設(shè)置了相應(yīng)的分組,那么在進(jìn)行跳轉(zhuǎn)的時(shí)候,一定要使用ARouter.getInstance().build(path, group)進(jìn)行跳轉(zhuǎn),否則無(wú)法找到相應(yīng)的跳轉(zhuǎn)

3.7重寫(xiě)跳轉(zhuǎn)URL實(shí)現(xiàn)重定向

可以重新定向你的URL地址

@Route(path = "/test/activity2")
public class PathReplaceServerImp implements PathReplaceService {
    @Override
    public String forString(String path) {

        path = "/test/activity2";
        return path;
    }

    @Override
    public Uri forUri(Uri uri) {
        return null;
    }

    @Override
    public void init(Context context) {
        Log.e("done", "init: 這里是初始化的時(shí)候執(zhí)行的方法");
    }
}

這里說(shuō)明一下:上面得path一定要加上一個(gè)任意項(xiàng)目中出現(xiàn)得注解即可,如果項(xiàng)目中沒(méi)有出現(xiàn)得話會(huì)報(bào)空指針異常的.通過(guò)上面的代碼,就可以更改項(xiàng)目中跳轉(zhuǎn)時(shí)候的path和URL地址了.

3.8ARouter攔截器

ARouter的攔截器可以在navigation的過(guò)程中攔截請(qǐng)求,并進(jìn)行一系列的處理 ,是一種AOP的編程模式(應(yīng)用場(chǎng)景為檢查登陸狀態(tài)等)要實(shí)現(xiàn)攔截器,首先我們需要實(shí)現(xiàn)IInterceptor接口,并使用Interceptor注解標(biāo)記我們的攔截器,并傳入priority優(yōu)先級(jí)參數(shù)(數(shù)字越小,優(yōu)先級(jí)越高),其實(shí)攔截器就是實(shí)現(xiàn)了一個(gè)接口去進(jìn)行回調(diào)的!

public class TestInterceotor implements IInterceptor {
    @Override
    public void process(Postcard postcard, final InterceptorCallback callback) {
        if (postcard.getPath().equals("/test/activity")) {
            callback.onContinue(postcard);
        } else {
            callback.onContinue(postcard);
        }
    }

    @Override
    public void init(Context context) {
        Log.e("done", "init: 初始化調(diào)用");
    }
}

這里說(shuō)明幾點(diǎn)內(nèi)容:

  • 首先process這個(gè)方法是處理攔截內(nèi)容的,這里我判斷了一個(gè)相應(yīng)的注解路由,如果跳轉(zhuǎn)的是相應(yīng)的路徑,那么進(jìn)行攔截.
  • 其次callback.onContinue(postcard)這個(gè)要注意,這句話的含義就是交由路由去處理,如果這里不寫(xiě)這句話的話,路由就終止了.
  • init方法是全局只執(zhí)行一次,這里為什么這么設(shè)計(jì)我也不知道,應(yīng)該是用到相應(yīng)的內(nèi)容了吧!原諒我是一個(gè)菜鳥(niǎo)
  • 如果你想加入相應(yīng)的等級(jí)的話在類的上面加入如下注解@Interceptor(priority = 7)其實(shí)就是設(shè)置攔截器等級(jí)的,這里為什么又?jǐn)r截器的等級(jí)呢?主要是為了讓攔截器一級(jí)一級(jí)的向下傳遞.這樣就有了多級(jí)的攔截器.

上面的內(nèi)容只是簡(jiǎn)單的用到了攔截器,但是理解起來(lái)畢竟又一些晦澀,當(dāng)直接說(shuō)讓你實(shí)現(xiàn)登陸的攔截,你怎么實(shí)現(xiàn),開(kāi)始的時(shí)候我也覺(jué)得簡(jiǎn)單,但是當(dāng)自己寫(xiě)的時(shí)候,我發(fā)現(xiàn)這個(gè)問(wèn)題真不是看上去那么簡(jiǎn)單.這里我先把內(nèi)容攔截器的代碼都放上,然后我在講解!

  • 首次跳轉(zhuǎn)的邏輯
        ARouter.getInstance().build("/test/activity").navigation(this, new NavCallback() {
            @Override
            public void onArrival(Postcard postcard) {

            }

            @Override
            public void onInterrupt(Postcard postcard) {
                Log.e(TAG, "onInterrupt: 這個(gè)方法是攔截器執(zhí)行之后才執(zhí)行的");
            }
        });
  • 攔截器的代碼:
@Interceptor(priority = 7)
public class TestInterceotor implements IInterceptor {
    @Override
    public void process(Postcard postcard, final InterceptorCallback callback) {
        if (postcard.getPath().equals("/test/activity")) {
            Log.e("done", "process: main2Activity");
            if (APP.isLogin) {/*已經(jīng)登陸*/
                callback.onContinue(postcard);
            } else {/*沒(méi)有登陸*/
                ARouter.getInstance().build("/test/activity2")
                        .withString("name", postcard.getPath()).navigation();
            }
            Log.e("done", "process: 執(zhí)行完了");
        } else {
            Log.e("done", "process: 這個(gè)方法什么時(shí)候執(zhí)行");
            callback.onContinue(postcard);
        }
    }

    @Override
    public void init(Context context) {
        Log.e("done", "init: 初始化調(diào)用");
    }
}
  • 模擬登陸的Activity
@Route(path = "/test/activity2")
public class Main3Activity extends AppCompatActivity {

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main3);
        ARouter.getInstance().inject(this);
    }

    public void click(View view) {
        APP.isLogin = true;
        ARouter.getInstance().build("/test/activity").navigation();
        finish();
    }
}

這里第一次跳轉(zhuǎn)的時(shí)候,由于攔截器使得沒(méi)有登陸的邏輯就跳轉(zhuǎn)到了登陸頁(yè)面,之后我在登陸頁(yè)面模擬了一次登陸的操作,然后關(guān)閉這個(gè)頁(yè)面之前,我又重新跳轉(zhuǎn)了目標(biāo)頁(yè)面,這次由于已經(jīng)登陸了,所以會(huì)直接繼續(xù)執(zhí)行跳轉(zhuǎn)了目標(biāo)頁(yè)面.這里說(shuō)的挺簡(jiǎn)單的,有一個(gè)回調(diào)我還沒(méi)有搞清楚,onInterrupt這個(gè)回調(diào)之后有什么用,其實(shí)這里也可以傳入一個(gè)字段,然后跳轉(zhuǎn)的時(shí)候直接傳入這個(gè)字段,這個(gè)字段主要是保存要跳轉(zhuǎn)的頁(yè)面的數(shù)據(jù),之后就能直接跳轉(zhuǎn)了.這樣就解決了耦合的問(wèn)題.

3.9在攔截器中添加額外的參數(shù)

@Route(path = "/test/activity", extras = 0;/*注意這里是int類型的參數(shù)*/)

說(shuō)明一下:這個(gè)是在目標(biāo)的Activity頁(yè)面添加的額外參數(shù),之后會(huì)在攔截器內(nèi)生效.

總結(jié)

其實(shí)關(guān)于這個(gè)框架還有很多問(wèn)題我沒(méi)有理解,但是基本的一些內(nèi)容都已經(jīng)講解了,其實(shí)接觸這個(gè)框架主要是當(dāng)初看見(jiàn)組件化開(kāi)發(fā)的時(shí)候,看到了這個(gè)框架,其實(shí)在項(xiàng)目中使用也可以,整體管理了跳轉(zhuǎn).寫(xiě)的挺亂的,感謝大家抽出寶貴時(shí)間來(lái)閱讀,有什么不對(duì)的地方希望指正.

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個(gè)濱河市哗咆,隨后出現(xiàn)的幾起案子蜘欲,更是在濱河造成了極大的恐慌,老刑警劉巖晌柬,帶你破解...
    沈念sama閱讀 222,729評(píng)論 6 517
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件姥份,死亡現(xiàn)場(chǎng)離奇詭異,居然都是意外死亡年碘,警方通過(guò)查閱死者的電腦和手機(jī)澈歉,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 95,226評(píng)論 3 399
  • 文/潘曉璐 我一進(jìn)店門(mén),熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái)盛泡,“玉大人闷祥,你說(shuō)我怎么就攤上這事。” “怎么了凯砍?”我有些...
    開(kāi)封第一講書(shū)人閱讀 169,461評(píng)論 0 362
  • 文/不壞的土叔 我叫張陵箱硕,是天一觀的道長(zhǎng)。 經(jīng)常有香客問(wèn)我悟衩,道長(zhǎng)剧罩,這世上最難降的妖魔是什么? 我笑而不...
    開(kāi)封第一講書(shū)人閱讀 60,135評(píng)論 1 300
  • 正文 為了忘掉前任座泳,我火速辦了婚禮惠昔,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘挑势。我一直安慰自己镇防,他們只是感情好,可當(dāng)我...
    茶點(diǎn)故事閱讀 69,130評(píng)論 6 398
  • 文/花漫 我一把揭開(kāi)白布潮饱。 她就那樣靜靜地躺著来氧,像睡著了一般。 火紅的嫁衣襯著肌膚如雪香拉。 梳的紋絲不亂的頭發(fā)上啦扬,一...
    開(kāi)封第一講書(shū)人閱讀 52,736評(píng)論 1 312
  • 那天,我揣著相機(jī)與錄音凫碌,去河邊找鬼扑毡。 笑死,一個(gè)胖子當(dāng)著我的面吹牛盛险,可吹牛的內(nèi)容都是我干的瞄摊。 我是一名探鬼主播,決...
    沈念sama閱讀 41,179評(píng)論 3 422
  • 文/蒼蘭香墨 我猛地睜開(kāi)眼枉层,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼泉褐!你這毒婦竟也來(lái)了?” 一聲冷哼從身側(cè)響起鸟蜡,我...
    開(kāi)封第一講書(shū)人閱讀 40,124評(píng)論 0 277
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤膜赃,失蹤者是張志新(化名)和其女友劉穎,沒(méi)想到半個(gè)月后揉忘,有當(dāng)?shù)厝嗽跇?shù)林里發(fā)現(xiàn)了一具尸體跳座,經(jīng)...
    沈念sama閱讀 46,657評(píng)論 1 320
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 38,723評(píng)論 3 342
  • 正文 我和宋清朗相戀三年泣矛,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了疲眷。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點(diǎn)故事閱讀 40,872評(píng)論 1 353
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡您朽,死狀恐怖狂丝,靈堂內(nèi)的尸體忽然破棺而出换淆,到底是詐尸還是另有隱情,我是刑警寧澤几颜,帶...
    沈念sama閱讀 36,533評(píng)論 5 351
  • 正文 年R本政府宣布倍试,位于F島的核電站,受9級(jí)特大地震影響蛋哭,放射性物質(zhì)發(fā)生泄漏县习。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 42,213評(píng)論 3 336
  • 文/蒙蒙 一谆趾、第九天 我趴在偏房一處隱蔽的房頂上張望躁愿。 院中可真熱鬧,春花似錦沪蓬、人聲如沸彤钟。這莊子的主人今日做“春日...
    開(kāi)封第一講書(shū)人閱讀 32,700評(píng)論 0 25
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)样勃。三九已至,卻和暖如春性芬,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背剧防。 一陣腳步聲響...
    開(kāi)封第一講書(shū)人閱讀 33,819評(píng)論 1 274
  • 我被黑心中介騙來(lái)泰國(guó)打工植锉, 沒(méi)想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留,地道東北人峭拘。 一個(gè)月前我還...
    沈念sama閱讀 49,304評(píng)論 3 379
  • 正文 我出身青樓俊庇,卻偏偏與公主長(zhǎng)得像,于是被迫代替她去往敵國(guó)和親鸡挠。 傳聞我的和親對(duì)象是個(gè)殘疾皇子辉饱,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 45,876評(píng)論 2 361

推薦閱讀更多精彩內(nèi)容