嗶哩嗶哩Android客戶端——多媒體選擇器boxing開源

開源過程是坎坷的白华,道路是曲折的走越,但前路是光明的椭豫。

Github鏈接--Bilibili/boxing

歡迎pypr,star旨指,issue赏酥。

開端

整個(gè)工程的開始于2015年。
回顧過去谆构,業(yè)務(wù)層和邏輯層是完全耦合的裸扶。
業(yè)務(wù)快速的迭代很容易令開發(fā)工作變快變糙變莽(技術(shù)水平未達(dá)標(biāo)也是原因之一),一次改版可能要對(duì)原有的代碼做侵入式修改搬素,而根據(jù)開/閉原則呵晨,這是不可接受的魏保。

舊問題

  • 由于設(shè)計(jì)欠缺優(yōu)雅性導(dǎo)致功能擴(kuò)展性差
  • 缺少單元測(cè)試無法保證程序的魯棒性
  • 業(yè)務(wù),邏輯和UI的代碼耦合嚴(yán)重

2016年開始重構(gòu)整個(gè)功能
目標(biāo)

  • 業(yè)務(wù)層摸屠,邏輯層和UI層分離
  • 只依賴基礎(chǔ)庫
  • 易于業(yè)務(wù)擴(kuò)展
  • 添加單元測(cè)試
  • 支持只使用Fragment

方案

  • 使用MVP模式
  • 只依賴support v4, v7
  • 通過接口和抽象類進(jìn)行依賴反轉(zhuǎn)
  • 使用Junit4 + Mokito + Espresso做測(cè)試

talk is free, show me the code.

時(shí)序圖

啟動(dòng)Activity的情況

boxing_sequenece.png

概要類圖

boxing_class.png

簡(jiǎn)潔起見谓罗,只畫出兩種關(guān)系,橫線是組合季二,豎線是繼承檩咱。根據(jù)依賴反轉(zhuǎn)原則,橫線指向的應(yīng)該是抽象類或者接口(圓形)胯舷。所以刻蚯,View層,Presenter層和Module層已經(jīng)分離了需纳。

設(shè)計(jì)接口

要只依賴于基礎(chǔ)庫芦倒,圖片加載庫和裁剪庫的實(shí)現(xiàn)就要分離出去,通過接口的形式在內(nèi)部使用不翩。

public interface IBoxingMediaLoader {
    /**
     * display thumbnail images for a ImageView.
     *
     * @param img     the display ImageView.
     * @param absPath the absolute path to display.
     * @param width   the resize with for the image.
     * @param height  the resize height for the image.
     */
    void displayThumbnail(@NonNull ImageView img, @NonNull String absPath, int width, int height);

    /**
     * display raw images for a ImageView, need more work to do.
     *
     * @param img      the display ImageView.
     * @param absPath  the absolute path to display.
     * @param callback the callback for the load result.
     */
    void displayRaw(@NonNull ImageView img, @NonNull String absPath, IBoxingCallback callback);
}
  • 加載縮略圖
    縮略圖是根據(jù)界面可以知道resize寬高兵扬,不需要回調(diào)。
  • 加載原圖
    原圖可能很大口蝠,很長(zhǎng)器钟,所有是沒有resize的,通過絕對(duì)路徑去解析顯示妙蔗,同時(shí)提供加載成功/失敗的回調(diào)傲霸。
public interface IBoxingCrop {

    /***
     * start crop operation.
     *
     * @param cropConfig  {@link BoxingCropOption}
     * @param path        the absolute path of media.
     * @param requestCode request code for the crop.
     */
    void onStartCrop(Context context, Fragment fragment, @NonNull BoxingCropOption cropConfig,
                     @NonNull String path, int requestCode);

    /**
     * get the result of cropping.
     *
     * @param resultCode the code in {@link android.app.Activity#onActivityResult(int, int, Intent)}
     * @param data       the data intent
     * @return the cropped image uri.
     */
    Uri onCropFinish(int resultCode, Intent data);
    }
  • 開始裁剪,啟動(dòng)者可能是Activity或Fragment眉反,需要額外的裁剪參數(shù)
  • 裁剪結(jié)束昙啄,通過Intent取到結(jié)果Uri

分離實(shí)現(xiàn)庫OK。

單元測(cè)試

單元測(cè)試的難易程度與耦合度成正比寸五,簡(jiǎn)而言之梳凛,優(yōu)雅的設(shè)計(jì)令單元測(cè)試的編寫變得簡(jiǎn)單。
構(gòu)造Mock類不再困難重重梳杏,接口方法實(shí)現(xiàn)單一功能韧拒,Presenter層和Model層的測(cè)試通過Junit4 + Mokito實(shí)現(xiàn),UI層通過Espresso實(shí)現(xiàn)十性。

Only Fragment

參考Google MVP叛溢,Activity只作為Presenter和View連接的載體,用Fragment實(shí)現(xiàn)View接口劲适,因此可以單獨(dú)使用Fragment作為功能主體楷掉。

   // 初始化AbsBoxingPickerFragment
    Boxing.get().setupFragment(AbsBoxingPickerFragment, new Boxing.OnFinishListener() {
        @Override
        public void onFinish(Intent intent, @Nullable List<BaseMedia> medias) {
           // 通過回調(diào)接口取到結(jié)果         
        }
    });

最后總結(jié)

抽象能力非常重要,需要不斷地練習(xí)减响。

UML圖很重要靖诗,強(qiáng)烈推薦Bob大叔的UML:Java程序員指南(雙語版)郭怪,暢快淋漓的閱讀快感。

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末刊橘,一起剝皮案震驚了整個(gè)濱河市鄙才,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌促绵,老刑警劉巖攒庵,帶你破解...
    沈念sama閱讀 216,470評(píng)論 6 501
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場(chǎng)離奇詭異败晴,居然都是意外死亡浓冒,警方通過查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 92,393評(píng)論 3 392
  • 文/潘曉璐 我一進(jìn)店門尖坤,熙熙樓的掌柜王于貴愁眉苦臉地迎上來稳懒,“玉大人,你說我怎么就攤上這事慢味〕“穑” “怎么了?”我有些...
    開封第一講書人閱讀 162,577評(píng)論 0 353
  • 文/不壞的土叔 我叫張陵纯路,是天一觀的道長(zhǎng)或油。 經(jīng)常有香客問我,道長(zhǎng)驰唬,這世上最難降的妖魔是什么顶岸? 我笑而不...
    開封第一講書人閱讀 58,176評(píng)論 1 292
  • 正文 為了忘掉前任,我火速辦了婚禮叫编,結(jié)果婚禮上辖佣,老公的妹妹穿的比我還像新娘。我一直安慰自己搓逾,他們只是感情好凌简,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,189評(píng)論 6 388
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著恃逻,像睡著了一般。 火紅的嫁衣襯著肌膚如雪藕施。 梳的紋絲不亂的頭發(fā)上寇损,一...
    開封第一講書人閱讀 51,155評(píng)論 1 299
  • 那天,我揣著相機(jī)與錄音裳食,去河邊找鬼矛市。 笑死,一個(gè)胖子當(dāng)著我的面吹牛诲祸,可吹牛的內(nèi)容都是我干的浊吏。 我是一名探鬼主播而昨,決...
    沈念sama閱讀 40,041評(píng)論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼,長(zhǎng)吁一口氣:“原來是場(chǎng)噩夢(mèng)啊……” “哼找田!你這毒婦竟也來了歌憨?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 38,903評(píng)論 0 274
  • 序言:老撾萬榮一對(duì)情侶失蹤墩衙,失蹤者是張志新(化名)和其女友劉穎务嫡,沒想到半個(gè)月后,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體漆改,經(jīng)...
    沈念sama閱讀 45,319評(píng)論 1 310
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡心铃,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,539評(píng)論 2 332
  • 正文 我和宋清朗相戀三年,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了挫剑。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片去扣。...
    茶點(diǎn)故事閱讀 39,703評(píng)論 1 348
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡,死狀恐怖樊破,靈堂內(nèi)的尸體忽然破棺而出愉棱,到底是詐尸還是另有隱情,我是刑警寧澤捶码,帶...
    沈念sama閱讀 35,417評(píng)論 5 343
  • 正文 年R本政府宣布羽氮,位于F島的核電站,受9級(jí)特大地震影響惫恼,放射性物質(zhì)發(fā)生泄漏档押。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,013評(píng)論 3 325
  • 文/蒙蒙 一祈纯、第九天 我趴在偏房一處隱蔽的房頂上張望令宿。 院中可真熱鬧,春花似錦腕窥、人聲如沸粒没。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,664評(píng)論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽癞松。三九已至,卻和暖如春入蛆,著一層夾襖步出監(jiān)牢的瞬間响蓉,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 32,818評(píng)論 1 269
  • 我被黑心中介騙來泰國打工哨毁, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留枫甲,地道東北人。 一個(gè)月前我還...
    沈念sama閱讀 47,711評(píng)論 2 368
  • 正文 我出身青樓,卻偏偏與公主長(zhǎng)得像想幻,于是被迫代替她去往敵國和親粱栖。 傳聞我的和親對(duì)象是個(gè)殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 44,601評(píng)論 2 353

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