中文字幕在线观看,亚洲а∨天堂久久精品9966,亚洲成a人片在线观看你懂的,亚洲av成人片无码网站,亚洲国产精品无码久久久五月天

Android路由實(shí)現(xiàn)

2018-07-20    來(lái)源:編程學(xué)習(xí)網(wǎng)

容器云強(qiáng)勢(shì)上線!快速搭建集群,上萬(wàn)Linux鏡像隨意使用

好了, 下面進(jìn)入今天的主題, 前幾個(gè)月有幸參加了CSDN組織的MDCC移動(dòng)開發(fā)者大會(huì), 一天下來(lái)我最大的收獲就是了解到了模塊化開發(fā), 回來(lái)之后我就一直在思考模塊化的一些優(yōu)點(diǎn), 不說(shuō)別的, 提供一種可插拔的開發(fā)方式就足夠我們興奮一會(huì)了~ 接下來(lái)自己開始嘗試了一些小demo, 發(fā)現(xiàn)在模塊化開發(fā)中最大的問(wèn)題就是組件間通訊, 例如: 在模塊化架構(gòu)中, 商城和個(gè)人中心分別是兩個(gè)獨(dú)立的模塊, 在開發(fā)階段, 個(gè)人中心如何想要跳轉(zhuǎn)商城的某個(gè)頁(yè)面咋辦? 這里就需要引入一個(gè)路由的概念了. 做過(guò)web開發(fā)的都知道, 在大部分web框架中url路由也是框架中很重要的組成部分, 如果大家對(duì)路由的概念還不是很清楚, 可以先來(lái)看一下我這篇 go web開發(fā)之url路由設(shè)計(jì)來(lái)了解下路由的概念, 這里稍稍解釋一下路由就是起到一個(gè)轉(zhuǎn)發(fā)的作用.

一張圖來(lái)體會(huì)一下路由的作用, 因?yàn)槲冶镜貨](méi)有UML工具, 新的還在下載中… 900M+, 我這網(wǎng)速有點(diǎn)受不了. 所以我選擇KolourPaint手動(dòng)繪制一張具有魔性的圖片先來(lái)體會(huì)一下.

自己實(shí)現(xiàn)一個(gè)路由的動(dòng)機(jī)

那到了我們Android開發(fā)中呢? 如果我們把項(xiàng)目模塊化了, 那兩個(gè)組件間進(jìn)行通訊或者跳轉(zhuǎn), 我們一般構(gòu)建Intent的方式就不再使用了, 很簡(jiǎn)單, 因?yàn)樵谀KA中根本找不到模塊B中的C類, 這就需要我們自定義路由規(guī)則, 繞一道彎去進(jìn)行跳轉(zhuǎn), 說(shuō)白了就是給你的類起一個(gè)別名, 我們用別用去引用. 其實(shí)在我準(zhǔn)備自己去實(shí)現(xiàn)一個(gè)路由的時(shí)候我是google了一些解決方案的, 這些方案大致可分為兩種.

  1. 完全自己實(shí)現(xiàn)路由, 完全封裝跳轉(zhuǎn)參數(shù)
  2. 利用隱式意圖跳轉(zhuǎn)

對(duì)于這兩種方式我總結(jié)了一下, 個(gè)人認(rèn)為第一種方式封裝的太多, 甚至有些框架是RESTFul like的, 這樣的封裝一是學(xué)習(xí)成本太高, 二是舊項(xiàng)目改動(dòng)起來(lái)太麻煩. 那第二種方式呢? 利用隱式意圖是一種不錯(cuò)的選擇, 而且Android原生支持, 這也是大家在嘗試模塊化開發(fā)時(shí)的一個(gè)選擇, 不過(guò)這種方式僅支持Activity, Service, BroadcastReceiver, 擴(kuò)展性太差. 綜上因素, 我還是決定自己實(shí)現(xiàn)一個(gè)路由, 參考自上面的局限性, 我們的路由具有一下2個(gè)特點(diǎn).

  1. 上手簡(jiǎn)單, 目標(biāo)是與原生方式一行代碼之差就能實(shí)現(xiàn)Activity, Service, BroadcastReceiver調(diào)用.
  2. 擴(kuò)展性強(qiáng), 開發(fā)者可以任意添加自己的路由實(shí)現(xiàn), 不僅僅局限于Activity, Service, BroadcastReceiver.

體驗(yàn)一下

在了解具體實(shí)現(xiàn)代碼之前, 我們先來(lái)了解一下新的路由怎么使用, 使用起來(lái)是不是符合上面兩點(diǎn), 首先我們先建立三個(gè)moduler, 分別是殼app, 商城模塊shoplib, bbs模塊bbslib. app模塊就是我們的殼了, 我們需要利用app模塊去打包, 而且app也是依賴shoplib和bbslib的, 所以我們可以在app的application里進(jìn)行路由的注冊(cè).

public class App extends Application {

    @Override
    public void onCreate() {
        super.onCreate();
        setupRouter();
    }

    private void setupRouter() {
        Router.router(ActivityRule.ACTIVITY_SCHEME + "shop.main", ShopActivity.class);
        Router.router(ActivityRule.ACTIVITY_SCHEME + "bbs.main", BBSActivity.class);
    }
}

這里注冊(cè)了兩個(gè)路由, 分別是商城模塊的的ShopActivity和bbs模塊的BBSActivity, 它們都是通過(guò) Router 類的靜態(tài)方法 router 方法進(jìn)行注冊(cè)的, 兩個(gè)參數(shù), 第一個(gè)參數(shù)是路由地址(也可以理解成別名), 第二個(gè)參數(shù)對(duì)應(yīng)的類. 注冊(cè)完了, 那接下來(lái)就是如何使用了, 我們來(lái)看看在商城模塊如何跳轉(zhuǎn)BBS模塊吧.

public class ShopActivity extends AppCompatActivity {

    @Override
    protected void onCreate(@Nullable Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        TextView tv = new TextView(this);
        tv.setTextSize(50);
        tv.setText("SHOP!!!");
        setContentView(tv);

        tv.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                Intent it = Router.invoke(ShopActivity.this, ActivityRule.ACTIVITY_SCHEME + "bbs.main");
                startActivity(it);
            }
        });
    }
}

主要代碼是在click事件里, 我們調(diào)用了 Router.invoke 方法, 第一個(gè)參數(shù)是當(dāng)前Activity, 第二個(gè)參數(shù)就是我們前面注冊(cè)的路由了, 這里都很好理解, 關(guān)鍵是看它的返回值, 這里直接返回了一個(gè)Intent, 這一點(diǎn)是最棒的~ 返回Intent也就是說(shuō)明下面的代碼和我們使用原生方式?jīng)]有任何區(qū)別! 這一點(diǎn)符合上面我們說(shuō)到的 上手簡(jiǎn)單 的目的.

至于第二點(diǎn)目標(biāo), 高擴(kuò)展性 , 大家可以實(shí)現(xiàn) Rule 接口自定義路由Rule, 然后調(diào)用 Router.addRule(String scheme, Rule rule) 方法進(jìn)行路由規(guī)則的注冊(cè). Rule接口的定義如下,

/**
 * 路由規(guī)則接口<br/>
 * Created by qibin on 2016/10/8.
 */

public interface Rule<T, V> {
    /**
     * 添加路由
     * @param pattern 路由uri
     * @param klass 路由class
     */
    void router(String pattern, Class<T> klass);

    /**
     * 路由調(diào)用
     * @param ctx Context
     * @param pattern 路由uri
     * @return {@code V} 返回對(duì)應(yīng)的返回值
     */
    V invoke(Context ctx, String pattern);
}

解釋一下, 首先是Rule接口的兩個(gè)范型, 第一個(gè)T是我們注冊(cè)的路由類型, 例如前面使用的Activity類型, 第二個(gè)V是 invoke 方法的返回值類型, 例如前面使用的Intent類型.至于自定義的代碼, 這里我賴了~, 沒(méi)有提供demo~~~ 大家可以嘗試自定義一下.

路由實(shí)現(xiàn)代碼

接下來(lái)我們開始進(jìn)入實(shí)現(xiàn)代碼環(huán)節(jié)~ 在來(lái)是代碼之前, 還是先來(lái)一張圖了解下這個(gè) Router 的結(jié)構(gòu).

帶著上面的圖片, 我們來(lái)看代碼, 首先我們來(lái)看看Router類, 畢竟我們?cè)谑褂玫臅r(shí)候都是在和Router打交道.

/**
 * Usage: <br />
 * <pre>
 * step 1. 調(diào)用Router.router方法添加路由
 * step 2. 調(diào)用Router.invoke方法根據(jù)pattern調(diào)用路由
 * </pre>
 * Created by qibin on 2016/10/9.
 */

public class Router {

    /**
     * 添加自定義路由規(guī)則
     * @param scheme 路由scheme
     * @param rule 路由規(guī)則
     * @return {@code RouterInternal} Router真實(shí)調(diào)用類
     */
    public static RouterInternal addRule(String scheme, Rule rule) {
        RouterInternal router = RouterInternal.get();
        router.addRule(scheme, rule);
        return router;
    }

    /**
     * 添加路由
     * @param pattern 路由uri
     * @param klass 路由class
     * @return {@code RouterInternal} Router真實(shí)調(diào)用類
     */
    public static <T> RouterInternal router(String pattern, Class<T> klass) {
        return RouterInternal.get().router(pattern, klass);
    }

    /**
     * 路由調(diào)用
     * @param ctx Context
     * @param pattern 路由uri
     * @return {@code V} 返回對(duì)應(yīng)的返回值
     */
    public static <V> V invoke(Context ctx, String pattern) {
        return RouterInternal.get().invoke(ctx, pattern);
    }
}

哈, Router的代碼很簡(jiǎn)單, 主要就是起到一個(gè)類似靜態(tài)代理的作用, 主要的代碼還是在 RouterInternal 里, 那來(lái)看看 RouterInternal 的結(jié)構(gòu)吧.

public class RouterInternal {

    private static RouterInternal sInstance;

    /** scheme->路由規(guī)則 */
    private HashMap<String, Rule> mRules;

    private RouterInternal() {
        mRules = new HashMap<>();
        initDefaultRouter();
    }

    /**
     * 添加默認(rèn)的Activity,Service,Receiver路由
     */
    private void initDefaultRouter() {
        addRule(ActivityRule.ACTIVITY_SCHEME, new ActivityRule());
        addRule(ServiceRule.SERVICE_SCHEME, new ServiceRule());
        addRule(ReceiverRule.RECEIVER_SCHEME, new ReceiverRule());
    }

    /*package */ static RouterInternal get() {
        if (sInstance == null) {
            synchronized (RouterInternal.class) {
                if (sInstance == null) {
                    sInstance = new RouterInternal();
                }
            }
        }

        return sInstance;
    }
}

首先 RouterInternal 是一個(gè)單例, 一個(gè) mRules 變量用來(lái)保存我們的路由規(guī)則, 在構(gòu)造中我們注冊(cè)了三個(gè)默認(rèn)的路由規(guī)則, 這三個(gè)路由規(guī)則想都不用想就知道是Activity, Service和BroadcastReceiver的. 接下來(lái)看看其他的方法.

/**
 * 添加自定義路由規(guī)則
 * @param scheme 路由scheme
 * @param rule 路由規(guī)則
 * @return {@code RouterInternal} Router真實(shí)調(diào)用類
 */
public final RouterInternal addRule(String scheme, Rule rule) {
    mRules.put(scheme, rule);
    return this;
}

addRule 方法是添加路由規(guī)則的實(shí)現(xiàn), 這里我們是直接向 mRules 這個(gè) HashMap 中添加的.

private <T, V> Rule<T, V> getRule(String pattern) {
    HashMap<String, Rule> rules = mRules;
    Set<String> keySet = rules.keySet();
    Rule<T, V> rule = null;
    for (String scheme : keySet) {
        if (pattern.startsWith(scheme)) {
            rule = rules.get(scheme);
            break;
        }
    }

    return rule;
}

getRule 的作用是根據(jù) pattern 來(lái)獲取規(guī)則, 這是一個(gè)私有的方法, 所以在使用的時(shí)候不需要關(guān)心, 它的原理很簡(jiǎn)單, 就是根據(jù)你的 pattern 來(lái)匹配 scheme 來(lái)獲取對(duì)應(yīng)的 Rule .

/**
 * 添加路由
 * @param pattern 路由uri
 * @param klass 路由class
 * @return {@code RouterInternal} Router真實(shí)調(diào)用類
 */
public final <T> RouterInternal router(String pattern, Class<T> klass) {
    Rule<T, ?> rule = getRule(pattern);
    if (rule == null) {
        throw new NotRouteException("unknown", pattern);
    }

    rule.router(pattern, klass);
    return this;
}

這個(gè) router 方法就是我們添加路由的實(shí)現(xiàn)了, 首先我們根據(jù)路由的uri來(lái)獲取對(duì)應(yīng)的 Rule , 然后調(diào)用該 Rule 的 router 方法, 至于 Rule.router 方法如何實(shí)現(xiàn)的, 我們稍后看~

/**
 * 路由調(diào)用
 * @param ctx Context
 * @param pattern 路由uri
 * @return {@code V} 返回對(duì)應(yīng)的返回值
 */
/*package*/ final <V> V invoke(Context ctx, String pattern) {
    Rule<?, V> rule = getRule(pattern);
    if (rule == null) {
        throw new NotRouteException("unknown", pattern);
    }

    return rule.invoke(ctx, pattern);
}

invoke 方法就是我們調(diào)用的時(shí)候執(zhí)行的代碼的, 返回值 T 是返回的 Rule 范型中指定的類型, 例如前面的 Intent .

綜上代碼, 我們發(fā)現(xiàn) RouterInternal 其實(shí)就是一個(gè)管理 Rule 的類, 具體的調(diào)用還是在各個(gè) Rule 中實(shí)現(xiàn), 上面提到過(guò), Rule 是一個(gè)接口, 它具有兩個(gè)范型, 分別對(duì)應(yīng)的調(diào)用 invoke 的返回值類型和我們要路由的類的類型. 解析來(lái)我們就來(lái)看看默認(rèn)的幾個(gè)路由規(guī)則是如何實(shí)現(xiàn)的.

對(duì)于Activity, Service, BroadcastReceiver的調(diào)用, 總結(jié)了一下, 它們其實(shí)都是返回的 Intent 類型, 所以我們可以先構(gòu)建一個(gè)指定返回值是 Intent 的Base類型.

/**
 * 返回Intent的路由規(guī)則的基類<br />
 * Created by qibin on 2016/10/9.
 */

public abstract class BaseIntentRule<T> implements Rule<T, Intent> {

    private HashMap<String, Class<T>> mIntentRules;

    public BaseIntentRule() {
        mIntentRules = new HashMap<>();
    }

    /**
     * {@inheritDoc}
     */
    @Override
    public void router(String pattern, Class<T> klass) {
        mIntentRules.put(pattern, klass);
    }

    /**
     * {@inheritDoc}
     */
    @Override
    public Intent invoke(Context ctx, String pattern) {
        Class<T> klass = mIntentRules.get(pattern);
        if (klass == null) { throwException(pattern);}
        return new Intent(ctx, klass);
    }

    /**
     * 當(dāng)找不到路由規(guī)則時(shí)拋出異常
     * @param pattern 路由pattern
     */
    public abstract void throwException(String pattern);
}

router 方法不多說(shuō), 還是向 Map 中添加鍵值對(duì), invoke 方法, 我們通過(guò)參數(shù)中的 pattern 從 mIntentRules 目標(biāo)類, 然后構(gòu)建一個(gè) Intent 返回, 最后一個(gè) throwException 是一個(gè)抽象方法, 用來(lái)在調(diào)用沒(méi)有 router 的類時(shí)拋出異常用~, 可以發(fā)現(xiàn), 其實(shí)大部分的實(shí)現(xiàn)在這里都實(shí)現(xiàn)了, 對(duì)于Activity繼承這個(gè) BaseIntentRule ,并且指定要路由類的類型是Activity, 并且實(shí)現(xiàn) throwException 方法就可以了.

/**
 * activity路由規(guī)則<br />
 * Created by qibin on 2016/10/8.
 */

public class ActivityRule extends BaseIntentRule<Activity> {

    /** activity路由scheme*/
    public static final String ACTIVITY_SCHEME = "activity://";

    /**
     * {@inheritDoc}
     */
    @Override
    public void throwException(String pattern) {
        throw new ActivityNotRouteException(pattern);
    }
}

ActivityRule 首先繼承了 BaseIntentRule 并指定了范型是 Activity , 實(shí)現(xiàn)的 throwException 方法也很簡(jiǎn)單, 就是拋出了一個(gè) ActivityNotRouteException 異常, 對(duì)于這個(gè)異常, 大家可以在文章最后的源碼下載部分找到~ 看完 ActivityRule 的實(shí)現(xiàn), 其實(shí)其他兩個(gè)默認(rèn) Rule 的實(shí)現(xiàn)都一樣了~ 大家也是自己去看代碼吧.

其實(shí)實(shí)現(xiàn)一個(gè)路由很簡(jiǎn)單, 原理就是給我們要路由的類定義一個(gè)別名, 然后在調(diào)用的地方通過(guò)別名去調(diào)用. 而且在封裝的時(shí)候盡量要符合現(xiàn)在用戶的使用習(xí)慣, 不要過(guò)多的封裝而忽略了使用者的感受.

 

來(lái)自:http://blog.csdn.net/qibin0506/article/details/53373412

 

標(biāo)簽: Google 代碼 開發(fā)者

版權(quán)申明:本站文章部分自網(wǎng)絡(luò),如有侵權(quán),請(qǐng)聯(lián)系:west999com@outlook.com
特別注意:本站所有轉(zhuǎn)載文章言論不代表本站觀點(diǎn)!
本站所提供的圖片等素材,版權(quán)歸原作者所有,如需使用,請(qǐng)與原作者聯(lián)系。

上一篇:安卓下的刮刮卡摸獎(jiǎng)的實(shí)現(xiàn)

下一篇:遷移Swift3.0爬坑與Swift交互OC之變化