XPage系列|這次升級(jí)后終于是全自動(dòng)化注冊(cè)了!

image

前言

作為 X-Library系列框架 的靈魂所在难述,XPage 開(kāi)源兩年以來(lái)题翻,一直致力于降低Fragment使用的難度蝶俱,努力實(shí)現(xiàn)一個(gè)Activity多Fragment的Android開(kāi)發(fā)模式帘腹。

就在前不久脚囊,我就整理了XPage開(kāi)源這幾年來(lái)的使用情況,寫(xiě)了一篇《史上最方便的Android頁(yè)面框架XPage使用指南》 ,并且還錄了幾期視頻單獨(dú)講解了XPage的使用 ,讓越來(lái)越多地人看到了XPage使用的便捷性静檬。

但就在前幾天,在交流群里突然有人問(wèn)我下面幾個(gè)問(wèn)題:

  • 1.我如果想在多個(gè)module中使用XPage并级,我該怎么辦呀拂檩?
  • 2.為什么我使用XPage之后,一直找不到AppPageConfig這個(gè)類俺氨獭稻励?

上面的問(wèn)題讓我突然認(rèn)識(shí)到一點(diǎn):并不是所有人都對(duì)APT技術(shù)有所了解的。

看來(lái)我之前參考ARouter實(shí)現(xiàn)的自動(dòng)注冊(cè)功能可能并沒(méi)有完善愈涩,難怪ARouter后來(lái)會(huì)寫(xiě)一個(gè)arouter-register插件來(lái)實(shí)現(xiàn)自動(dòng)注冊(cè)的功能望抽。

于是乎,為了能夠讓XPage的自動(dòng)注冊(cè)功能更加完美履婉,我加班加點(diǎn)開(kāi)發(fā)煤篙,于是就有了XPage的3.1.1版本--徹底的自動(dòng)化注冊(cè)

升級(jí)后有什么變化

在感受全自動(dòng)化頁(yè)面注冊(cè)帶來(lái)的便利之前毁腿,讓我們先來(lái)感受一下之前版本的使用辑奈。

3.1.1之前版本

在3.1.1之前版本,在使用自動(dòng)注冊(cè)功能的時(shí)候已烤,還是需要實(shí)現(xiàn)PageConfiguration接口鸠窗,并調(diào)用編譯時(shí)自動(dòng)生成的頁(yè)面配置類“moduleName”+PageConfig 的getPages()方法返回注冊(cè)的頁(yè)面。

PageConfig.getInstance()
        .setPageConfiguration(new PageConfiguration() { //頁(yè)面注冊(cè)
            @Override
            public List<PageInfo> registerPages(Context context) {
                //自動(dòng)注冊(cè)頁(yè)面,是編譯時(shí)自動(dòng)生成的胯究,build一下就出來(lái)了塌鸯。如果你還沒(méi)使用@Page的話,暫時(shí)是不會(huì)生成的唐片。
                return AppPageConfig.getInstance().getPages(); //自動(dòng)注冊(cè)頁(yè)面
            }
        })
        .debug("PageLog")       //開(kāi)啟調(diào)試
        .setContainActivityClazz(XPageActivity.class) //設(shè)置默認(rèn)的容器Activity
        .enableWatcher(false)   //設(shè)置是否開(kāi)啟內(nèi)存泄露監(jiān)測(cè)
        .init(this); 

可以看到丙猬,這里的自動(dòng)注冊(cè)還是需要一部分手動(dòng)配合才能完成的。如果說(shuō)你當(dāng)前只有一個(gè)module的話费韭,可能還好說(shuō)茧球。但是如果你使用了多個(gè)module之后,你就需要把多個(gè)module生成的配置類像上面那樣一個(gè)一個(gè)地加進(jìn)去星持,這樣用起來(lái)會(huì)讓人感覺(jué)非常的不方便抢埋,這明顯違背了我寫(xiě)XPage框架的初衷!

不僅如此督暂,這樣寫(xiě)死還會(huì)帶來(lái)其他很多問(wèn)題:

  • 1.如果module名變了揪垄,還需要對(duì)應(yīng)地去修改配置類的類名。
  • 2.如果當(dāng)前module沒(méi)有使用@Page注解修飾Fragment的話逻翁,配置類也不會(huì)自動(dòng)生成饥努,這樣會(huì)讓很多初次使用者非常疑惑。
  • 3.項(xiàng)目要是沒(méi)有編譯過(guò)的話八回,配置類是不會(huì)自動(dòng)生成的酷愧,這樣代碼就會(huì)報(bào)錯(cuò)說(shuō)類找不到,然后很多新手就懵逼了缠诅。

3.1.1之后版本

為了能夠解決以上的問(wèn)題溶浴,我實(shí)現(xiàn)了一個(gè)自動(dòng)注冊(cè)的配置類AutoPageConfiguration 。那么下面就看一下最新版本的XPage是如何注冊(cè)的吧:

PageConfig.getInstance()
        .debug("PageLog")       //開(kāi)啟調(diào)試
        .setContainActivityClazz(XPageActivity.class) //設(shè)置默認(rèn)的容器Activity管引,按需設(shè)置(非必須)
        .init(this);            //初始化頁(yè)面配置

是的士败,你沒(méi)有看錯(cuò),這里沒(méi)有手動(dòng)實(shí)現(xiàn)PageConfiguration接口的部分了褥伴,可以說(shuō)是真正實(shí)現(xiàn)了全自動(dòng)頁(yè)面注冊(cè)谅将,是不是非常方便呀?

image

如何實(shí)現(xiàn)注冊(cè)的自動(dòng)化

看到上面的變化噩翠,你是不是非常想知道我是如何實(shí)現(xiàn)徹底的自動(dòng)化注冊(cè)的戏自?

想要回答這個(gè)問(wèn)題,還是讓我們先看一看這個(gè)編譯時(shí)自動(dòng)生成的配置類是如何實(shí)現(xiàn)的伤锚。

APT技術(shù)實(shí)現(xiàn)頁(yè)面配置類的自動(dòng)生成

其實(shí)當(dāng)初實(shí)現(xiàn)頁(yè)面配置類的自動(dòng)生成的方案擅笔,也是我研讀了ARouter源碼之后,受到了APT技術(shù)的啟發(fā)后完成的屯援。

因?yàn)閄Page實(shí)現(xiàn)路由跳轉(zhuǎn)主要就是靠 PageInfo 和 Fragment 建立起來(lái)的映射關(guān)系猛们。當(dāng)時(shí)的思路就是采用APT技術(shù),利用@Page注解去標(biāo)識(shí)需要注冊(cè)的Fragment狞洋,然后在編譯的時(shí)候通過(guò)APT技術(shù)去掃描出所有使用了@Page注解標(biāo)識(shí)了的Fragment弯淘,將注解信息轉(zhuǎn)化為PageInfo, 并按module生成對(duì)應(yīng)的頁(yè)面配置類,在這個(gè)配置類里面存放了該module下所有標(biāo)注了@Page的頁(yè)面信息PageInfo吉懊。

下面是自動(dòng)生成的一個(gè)簡(jiǎn)單的配置類例子:

image

可以看到庐橙,自動(dòng)生成的配置類都會(huì)存放在com.xuexiang.xpage.config包下假勿,類名都是以PageConfig作為結(jié)尾。注意這里非常關(guān)鍵态鳖,它是我后面實(shí)現(xiàn)自動(dòng)化注冊(cè)的關(guān)鍵转培。

詳細(xì)的實(shí)現(xiàn)細(xì)節(jié),可以參見(jiàn)XPage的頁(yè)面配置自動(dòng)生成器PageConfigProcessor的源碼 浆竭。

運(yùn)行時(shí)掃描指定包下的配置類反射實(shí)現(xiàn)自動(dòng)注冊(cè)

上面我們?cè)诹私忭?yè)面配置類是如何自動(dòng)生成的時(shí)候發(fā)現(xiàn)一個(gè)規(guī)律:

自動(dòng)生成的配置類都會(huì)存放在com.xuexiang.xpage.config包下浸须,類名都是以PageConfig作為結(jié)尾。

那么我們可不可以在運(yùn)行的時(shí)候邦泄,直接掃描com.xuexiang.xpage.config包下的所有類删窒,然后找到以PageConfig作為結(jié)尾的配置類,然后反射它的getPages方法直接獲取到所有的配置信息顺囊,然后注冊(cè)進(jìn)去肌索?

下面是我根據(jù)上面的猜想,實(shí)現(xiàn)的AutoPageConfiguration類源碼:

public class AutoPageConfiguration implements PageConfiguration {
    /**
     * 頁(yè)面配置所在的包名
     */
    private static final String PAGE_CONFIG_PACKAGE_NAME = "com.xuexiang.xpage.config";
    /**
     * 頁(yè)面配置生成類的類后綴名
     */
    private static final String PAGE_CONFIG_CLASS_NAME_SUFFIX = "PageConfig";

    @Override
    public List<PageInfo> registerPages(Context context) {
        List<PageInfo> pageInfos = new ArrayList<>();
        Set<String> classSet = null;
        try {
            classSet = ClassUtils.getClassNames(context, PAGE_CONFIG_PACKAGE_NAME);
        } catch (Exception e) {
            e.printStackTrace();
        }
        if (classSet != null) {
            for (String className : classSet) {
                if (className != null && className.endsWith(PAGE_CONFIG_CLASS_NAME_SUFFIX)) {
                    try {
                        pageInfos.addAll(getPagesByClass(Class.forName(className)));
                    } catch (Exception e) {
                        PageLog.e(e);
                    }
                }
            }
        }
        return pageInfos;
    }

    private List<PageInfo> getPagesByClass(Class<?> clazz) throws Exception {
        // 獲取單例對(duì)象
        Method getInstanceMethod = clazz.getDeclaredMethod("getInstance");
        getInstanceMethod.setAccessible(true);
        Object instance = getInstanceMethod.invoke(null);
        // 獲取頁(yè)面信息
        Method getPagesMethod = clazz.getDeclaredMethod("getPages");
        getPagesMethod.setAccessible(true);
        return (List<PageInfo>) getPagesMethod.invoke(instance);
    }
}

從源碼中我們可以看到包蓝,我是這樣做的:

  • 1.使用ClassUtils.getClassNames獲取到com.xuexiang.xpage.config包下的所有類的類名驶社。這里的ClassUtils也是我借鑒了ARouter里面的源碼。
  • 2.遍歷這個(gè)類名集合测萎,并根據(jù)類名結(jié)尾是否是PageConfig篩選出所有的配置類亡电。
  • 3.調(diào)用getPagesByClass方法,反射獲取到配置類的所有頁(yè)面信息硅瞧,然后加入到頁(yè)面集合中份乒,最終返回所有module配置頁(yè)面的信息。

有了AutoPageConfiguration之后腕唧,下面就非常簡(jiǎn)單啦或辖,我們只需要將mPageConfiguration默認(rèn)設(shè)置成AutoPageConfiguration,這樣就可以實(shí)現(xiàn)自動(dòng)化注冊(cè)啦枣接!

/**
 * 初始化頁(yè)面信息
 *
 * @param context 上下文
 */
private void initPages(Context context) {
    if (mPageConfiguration == null) {
        // 沒(méi)有設(shè)置的話颂暇,就使用自動(dòng)注冊(cè)配置
        mPageConfiguration = new AutoPageConfiguration();
    }
    registerPageInfos(mPageConfiguration.registerPages(context));
    CoreConfig.init(context, getPages());
}

增加混淆配置

你以為到這兒就結(jié)束了?沒(méi)那么簡(jiǎn)單但惶!可以發(fā)現(xiàn)耳鸯,上面的實(shí)現(xiàn)方案主要是依賴于掃描類并進(jìn)行反射注冊(cè)的。所以如果代碼做了混淆了之后膀曾,該方案就會(huì)失效了县爬,所以我們還需要在混淆配置清單中增加如下的配置來(lái)避免混淆:

-keep class com.xuexiang.xpage.config.** { *; }

我們要保證com.xuexiang.xpage.config包下的類不能被混淆。

到這兒添谊,自動(dòng)注冊(cè)的實(shí)現(xiàn)算是真正的講完了财喳,下面讓我們來(lái)瞧瞧XPage的新版本還有那些地方更新了!

image

其他更新

去除LeakCanary依賴

在此之前,XPage一直依賴了LeakCanary耳高,主要原因還是LeakCanary在2.0版本之前的使用還是相當(dāng)不方便的扎瓶,于是我就做了一下默認(rèn)集成以方便使用。

但是當(dāng)LeakCanary升級(jí)到2.0以上版本的時(shí)候祝高,這個(gè)問(wèn)題似乎就沒(méi)了栗弟。因?yàn)檫M(jìn)行了重新的設(shè)計(jì),LeakCanary的使用變得沒(méi)那么具有侵入性工闺,因此我就考慮去除了LeakCanary的依賴。

優(yōu)化了頁(yè)面點(diǎn)擊的鍵盤處理

之前在XPageActivity里面做了簡(jiǎn)單的頁(yè)面點(diǎn)擊處理:當(dāng)用戶點(diǎn)擊到非輸入框區(qū)域就隱藏鍵盤瓣蛀。

但是這樣做了之后發(fā)現(xiàn)效果并不是很好陆蟆,因?yàn)橛行╉?yè)面可能并不需要這個(gè)功能,如果把這個(gè)寫(xiě)到Activity里面的話惋增,那么在這個(gè)Activity下的所有Fragment都將擁有這個(gè)功能叠殷,這樣非常不靈活。

除此之外诈皿,使用者可能也想自定義屏幕的觸摸事件林束,因此我對(duì)此做了重新設(shè)計(jì),將觸摸事件的處理下放至每個(gè)Fragment之中稽亏,由Activity調(diào)用指定的方法進(jìn)行處理壶冒。

相關(guān)鏈接

最后

非常感謝大家對(duì)XPage 的支持,喜歡的小伙伴可以到項(xiàng)目的Github主頁(yè):https://github.com/xuexiangjys/XPage 點(diǎn)擊star支持一下哦截歉!

更多資訊內(nèi)容胖腾,歡迎微信搜索公眾號(hào):「我的Android開(kāi)源之旅」

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個(gè)濱河市瘪松,隨后出現(xiàn)的幾起案子咸作,更是在濱河造成了極大的恐慌,老刑警劉巖宵睦,帶你破解...
    沈念sama閱讀 218,386評(píng)論 6 506
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件记罚,死亡現(xiàn)場(chǎng)離奇詭異,居然都是意外死亡壳嚎,警方通過(guò)查閱死者的電腦和手機(jī)桐智,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 93,142評(píng)論 3 394
  • 文/潘曉璐 我一進(jìn)店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái)诬辈,“玉大人酵使,你說(shuō)我怎么就攤上這事”涸悖” “怎么了口渔?”我有些...
    開(kāi)封第一講書(shū)人閱讀 164,704評(píng)論 0 353
  • 文/不壞的土叔 我叫張陵,是天一觀的道長(zhǎng)穿撮。 經(jīng)常有香客問(wèn)我缺脉,道長(zhǎng)痪欲,這世上最難降的妖魔是什么? 我笑而不...
    開(kāi)封第一講書(shū)人閱讀 58,702評(píng)論 1 294
  • 正文 為了忘掉前任攻礼,我火速辦了婚禮业踢,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘礁扮。我一直安慰自己知举,他們只是感情好,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,716評(píng)論 6 392
  • 文/花漫 我一把揭開(kāi)白布太伊。 她就那樣靜靜地躺著雇锡,像睡著了一般。 火紅的嫁衣襯著肌膚如雪僚焦。 梳的紋絲不亂的頭發(fā)上锰提,一...
    開(kāi)封第一講書(shū)人閱讀 51,573評(píng)論 1 305
  • 那天,我揣著相機(jī)與錄音芳悲,去河邊找鬼立肘。 笑死,一個(gè)胖子當(dāng)著我的面吹牛名扛,可吹牛的內(nèi)容都是我干的谅年。 我是一名探鬼主播,決...
    沈念sama閱讀 40,314評(píng)論 3 418
  • 文/蒼蘭香墨 我猛地睜開(kāi)眼罢洲,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼踢故!你這毒婦竟也來(lái)了?” 一聲冷哼從身側(cè)響起惹苗,我...
    開(kāi)封第一講書(shū)人閱讀 39,230評(píng)論 0 276
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤殿较,失蹤者是張志新(化名)和其女友劉穎,沒(méi)想到半個(gè)月后桩蓉,有當(dāng)?shù)厝嗽跇?shù)林里發(fā)現(xiàn)了一具尸體淋纲,經(jīng)...
    沈念sama閱讀 45,680評(píng)論 1 314
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,873評(píng)論 3 336
  • 正文 我和宋清朗相戀三年院究,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了洽瞬。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點(diǎn)故事閱讀 39,991評(píng)論 1 348
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡业汰,死狀恐怖伙窃,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情样漆,我是刑警寧澤为障,帶...
    沈念sama閱讀 35,706評(píng)論 5 346
  • 正文 年R本政府宣布,位于F島的核電站,受9級(jí)特大地震影響鳍怨,放射性物質(zhì)發(fā)生泄漏呻右。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,329評(píng)論 3 330
  • 文/蒙蒙 一鞋喇、第九天 我趴在偏房一處隱蔽的房頂上張望声滥。 院中可真熱鬧,春花似錦侦香、人聲如沸落塑。這莊子的主人今日做“春日...
    開(kāi)封第一講書(shū)人閱讀 31,910評(píng)論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)芜赌。三九已至,卻和暖如春伴逸,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背膘壶。 一陣腳步聲響...
    開(kāi)封第一講書(shū)人閱讀 33,038評(píng)論 1 270
  • 我被黑心中介騙來(lái)泰國(guó)打工错蝴, 沒(méi)想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留,地道東北人颓芭。 一個(gè)月前我還...
    沈念sama閱讀 48,158評(píng)論 3 370
  • 正文 我出身青樓顷锰,卻偏偏與公主長(zhǎng)得像,于是被迫代替她去往敵國(guó)和親亡问。 傳聞我的和親對(duì)象是個(gè)殘疾皇子官紫,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 44,941評(píng)論 2 355

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