[譯] 如何創建高度模塊化的 Android 應用

HerbertShar 8年前發布 | 5K 次閱讀 Android開發 移動開發 RecyclerView

Android 中構建 UI 的職責通常委派給一個類(比如 Activity、Fragment 或 View/Presenter)。這通常涉及到以下任務:

  • 填充 View(xml 布局)
  • View 配置(運行時參數、布局管理、適配)
  • 數據源連接(DB 或者 數據存儲的監聽/訂閱)
  • 加載緩存數據
  • 新數據的按需請求分派
  • 監聽用戶事件(tap、scroll)然后響應事件

除此之外,Activity 和 Fragment 通常還會委派一些額外的職責:

  • App 導航
  • Activity 結果處理
  • Google Play 服務連接和交互
  • 過渡動畫配置

這不是單一職責,當前的處理方式包括了繼承或組合,這太復雜了。

繼承地獄

“當一個對象或類是基于另一個對象或類,這就是繼承。它是為了代碼重用,并允許原始軟件通過公共類和接口單獨擴展。這些對象或類的關系,通過繼承形成一種層級。”

( en.wikipedia.org/wiki/Inheritance_(object-oriented_programming) )

對于這種復雜的結構,如 UI 構建,繼承能讓它很快變成一坨 x。看看下面的模擬案例:

據此繼承樹構建代碼會很快變得難于管理 ("繼承地獄")。要避免這種情況,開發人員應遵循"組合而非繼承"的原則。

組合優于繼承

“在面向對象編程中有個原則,組合替代繼承(組合復用原則)。類應該通過組合實現行為多態和代碼復用(通過包含其他類的實例來實現所需的功能)。”( en.wikipedia.org/wiki/Composition_over_inheritance )

組合優于繼承原則是個很棒的想法,無疑可以幫助我們解決上面提出的問題。然而,幾乎沒有庫、示例代碼或者教程來教你如何在 Android 上實現這原則。一種實現它的簡單方法就是使用運行時參數(又叫 intent extras)來組合功能,但是,仍會導致形成一個巨大的難以管理的怪物類。

很榮幸,這里要提及兩個庫, LightCycleCompositeAndroid 。兩者都緊緊的綁定在 Activity 或 Fragment,拋開其他諸如 MVP 或 MVVM 的現代模式,都不是很靈活,因為它們僅僅依賴 Android 原生回調(無法添加額外回調),也不支持模塊間通信。

修飾模式

開發者們每天都要面對這些提出的問題, EyeEm Android 團隊開始開發一種模式,以一種更加靈活的方式來解決該問題,而不是直接附加到一個組件上如 Activity 或 Fragment 。該模式可以用來對任何開發者希望通過組合來模塊化的類進行解耦。

該模式和 LightCycle/Composite 的方法非常相似,由三個類組成:

  • 基本類,稱為 DecoratedObject(裝飾對象),調度其繼承和額外的方法給一個調度對象。
  • DecoratorsObject 實例化,保存所有組成對象的列表并分派方法給它們。
  • Decorator 抽象類,所有方法和額外接口都只聲明未實現。由創建此類的開發人添加單一職責的具體實現。

使用這種方式開發人員獲得的直接好處

  • 職責分離
  • 功能動態運行置換
  • 并行開發

為了讓開發者能毫無障礙的實現上述模式,一個在編譯時生成代碼的工具被創造了出來,接下來我們會看到,將之前提交的那些職責分解成單一職責類是多么簡單。

Decorator 庫

如何三步創建你自己的模塊化單一職責應用

要實現裝飾模式首先創建應生成的代碼藍圖,在這里我們將使用一個帶 RecyclerView 的 Activity 作為例子,但同樣能用在 Fragment、Presenter 甚至 View 。這這個例子中,我們將使用 activity 生命周期中的 onCreate/onStart/onStop/onDestroy ,但是也會額外創建幾個適合 RecyclerView 案例的回調。

@Decorate
    public class ActivityBlueprint extends AppCompatActivity {

        @Override protected void onCreate(@Nullable Bundle savedInstanceState) {super.onCreate(savedInstanceState);}
        @Override protected void onStart() {super.onStart();}
        @Override protected void onStop() {super.onStop();}
        @Override protected void onDestroy() {super.onDestroy();}

        public int getLayoutId() {return R.layout.recycler_view;}
        public RecyclerView.LayoutManager getLayoutManager() {return new LinearLayoutManager(this);}
        public RecyclerView.Adapter getAdapter() {return null;}
        public void setupRecyclerView(RecyclerView recyclerView, WrapAdapter wrapAdapter, RecyclerView.Adapter adapter) { /**/ }

        public interface DataInstigator {
            RealmList getList();
            RealmObject getData();
        }

        public interface RequestInstigator {
            void reload();
            void loadMore();
        }
    }

這個簡單的藍圖使用 @Decorate 注解,將會生成完整的修飾模式實現, Serializable builder 類可以作為參數傳遞。為了完成 Activity 的實現,我們擴展了生成類,并將 received builder 綁定上去。

public classRecyclerViewActivityextendsDecoratedAppCompatActivity{

        @Overrideprotected void onCreate(Bundle savedInstanceState) {
            bind(getBuilder(getIntent().getSerializableExtra(KEY.BUILDER)));
            super.onCreate(savedInstanceState);
            setContentView(getLayoutId());
            RecyclerView rv = (RecyclerView) findViewById(R.id.recycler);
            rv.setLayoutManager(getLayoutManager());
            RecyclerView.Adapter adapter = getAdapter();
            WrapAdapter wrapAdapter = newWrapAdapter(adapter);
            rv.setAdapter(wrapAdapter);
            setupRecyclerView(rv, wrapAdapter, adapter);
        }

        @Overrideprotected void onDestroy() {
            super.onDestroy();
            unbind();
        }
    }

現在可以方便的將職責分發到可綁定的修飾類上。每個修飾器包含所有生命周期的回調,可以實現任何可選接口。最后,可以組合得到一個簡單的建造者模式:

Intent i = new Intent(context, RecyclerViewActivity.class);
            i.putExtra(KEY.BUILDER, new DecoratedActivity.Builder()
                    .addDecorator(GridInstigator.class)
                    .addDecorator(LoadMoreDecorator.class)
                    .addDecorator(PhotoGridAdapter.class)
                    .addDecorator(PhotoListInstigator.class)
                    .addDecorator(PhotoRequestInstigator.class));
            i.putExtra(KEY.URL, url);

完整示例應用

請查看我們 Github 上的相關庫和完整的示例應用 https://github.com/eyeem/decorator 。該示例應用在開始下一步之前從當前 activity 通過簡單的添加/移除修飾器來模擬每個用戶在 Activity 執行 tap。

上面展示的代碼大部分都是出自示例。你會發現一個用 Realm 和 Retrofit 真正實現的修飾器列表,就是這篇文章開始提到的 UI 構建任務。

  • CoordinatorLayoutInstigator,重寫了 CoordinatorLayout 的默認布局,可選實例化一個 header
  • ToolbarInstigator,接管 toolbar,并且應用一個標題
  • ToolbarUp 和 ToolbarBack 修飾器,導航工具欄上圖標的行為
  • 加載更多的修飾器,添加一個無限滾動的功能到 RecyclerView
  • PhotoList 和 PhotoRequest 修飾器,本地數據存儲和 API 請求圖片列表 API 調用

現實世界應用

EyeEm 已經在使用修飾器——并且體驗非常好。來 Play Store 看看吧。我們目前為所有 UI 元素使用 裝飾 view presenters(使用 Square Mortar 庫),為過渡動畫使用了裝飾 activities,處理不同 API 級別,A/B 測試,導航,跟蹤和新攝影師入職時的少數特殊情況,

最后說明

上面所示的代碼和實現純粹只是示例,僅作為指導。

當我們為 Android 創建這個庫時,該模式是開放給任何用例的。這個庫是一個純 Java 實現,它在編譯時生成代碼,可用于任何 Java 類,我們鼓勵開發人員在他們任何 Java 項目中編寫模塊化的單一職責的代碼!來

說的夠多了-將 添加到你的 build.gradle 中,然后開始構建模塊化應用吧。

EyeEm ,我們正在探索攝影和技術的交叉點。除了建立尖端的計算機視覺技術,我們的 iOS,Android 和 web 應用程序被 1800 萬世界各地的攝影師用于獲得靈感、 學習、 分享他們的工作,發現驚人的天賦,獲得出版和展出,甚至通過我們的市場賺錢。

 

 

來自:http://www.jianshu.com/p/458796dc2a8d

 

 本文由用戶 HerbertShar 自行上傳分享,僅供網友學習交流。所有權歸原作者,若您的權利被侵害,請聯系管理員。
 轉載本站原創文章,請注明出處,并保留原始鏈接、圖片水印。
 本站是一個以用戶分享為主的開源技術平臺,歡迎各類分享!