<output id="qn6qe"></output>

    1. <output id="qn6qe"><tt id="qn6qe"></tt></output>
    2. <strike id="qn6qe"></strike>

      亚洲 日本 欧洲 欧美 视频,日韩中文字幕有码av,一本一道av中文字幕无码,国产线播放免费人成视频播放,人妻少妇偷人无码视频,日夜啪啪一区二区三区,国产尤物精品自在拍视频首页,久热这里只有精品12

      安卓筆記俠

      專注安卓開發

      導航

      模塊化(1):基本思路

      一.什么是模塊化

        什么是模塊化呢?有一種定義是:模塊化是一種處理復雜系統分解為更好的可管理模塊的方式。由此可見,模塊化思路下構成的復雜系統是由各個可管理的子模塊構成的,每個子模塊之前相互獨立,并通過某種特定的方式進行通信。
      在工業上面,有模塊化汽車的概念,也有模塊化手機的概念,各個模塊根據一定的標準進行生產,生產之后可以直接進行各個模塊的組裝,某個模塊出現問題之后,可以單獨對這個模塊進行替換。舉個例子,同樣一款汽車,有各中配置不同的版本,比如發動機不同。這些發動機都按照一定的標準生產,但是發送的輸出和能耗并不同。重要的是其接口標準一樣。從可替換這一點來講,和軟件開發中的可插拔是異曲同工的。

      Android 開發中有兩個比較相似的概念:組件化和模塊化,這里需要進行區分的。

      組件化:指的是單一的功能組件,如地圖組件、支付組件、路由組件(Router)等等;
      模塊化:獨立的業務模塊,模塊相對于組件來講粒度更大。

      模塊化的好處是顯而易見的。

      ? 多團隊并行開發測試;
      ? 模塊間解耦、重用;
      ? 可單獨編譯打包某一模塊,提升開發效率。

      Android 插件化 ——指將一個程序劃分為不同的部分,比如一般 App的皮膚樣式就可以看成一個插件

      Android 組件化 ——這個概念實際跟上面相差不那么明顯,組件和插件較大的區別就是:組件是指通用及復用性較高的構件,比如圖片緩存就可以看成一個組件被多個 App共用

      插件的方式只有三種:1,apk安裝,2,apk不安裝,3,dex包

       

      二.模塊Debug和Release處理

        對于模塊化項目,每個單獨的 Business Module 都可以單獨編譯成 APK。在開發階段需要單獨打包編譯,項目發布的時候又需要它作為項目的一個 Module 來整體編譯打包。簡單的說就是開發時是 Application,發布時是 Library。因此需要在 Business Module 的 build.gradle 中加入如下代碼:

      if(isBuildModule.toBoolean()){
         apply plugin: 'com.android.application'
      }else{
         apply plugin: 'com.android.library'
      }

      isBuildModule 在項目根目錄的 gradle.properties 中定義:

      isBuildModule=false

      同樣 Manifest.xml 也需要有兩套:

      sourceSets {
        main {
            if (isBuildModule.toBoolean()) {
                manifest.srcFile 'src/main/debug/AndroidManifest.xml'
            } else {
                manifest.srcFile 'src/main/release/AndroidManifest.xml'
            }
        }
      }

      debug 模式下的 AndroidManifest.xml :

       1 <manifest xmlns:android="http://schemas.android.com/apk/res/android"
       2    package="com.dajiazhongyi.dajia.pedumodule">
       3 
       4    <uses-permission android:name="android.permission.INTERNET" />
       5    <uses-permission android:name="android.permission.READ_PHONE_STATE" />
       6    <uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
       7    <uses-permission android:name="android.permission.ACCESS_WIFI_STATE" />
       8    <uses-permission android:name="android.permission.CHANGE_WIFI_STATE" />
       9 
      10    <application
      11        ...
      12        >
      13 
      14        <activity
      15            android:name="com.dajiazhongyi.dajia.loginmodule.ui.DaJiaLauncher"
      16            android:exported="true"
      17            android:screenOrientation="portrait">
      18            <intent-filter>
      19                <action android:name="android.intent.action.MAIN" />
      20                <category android:name="android.intent.category.LAUNCHER" />
      21            </intent-filter>
      22            <intent-filter>
      23                <action android:name="android.intent.action.VIEW" />
      24 
      25                <category android:name="android.intent.category.DEFAULT" />
      26                <category android:name="android.intent.category.BROWSABLE" />
      27 
      28                <data android:scheme="dajia" />
      29            </intent-filter>
      30        </activity>
      31 
      32        <activity
      33            android:name=".ui.MainActivity"
      34            android:screenOrientation="portrait"/>
      35 
      36    </application>
      37 
      38 </manifest>

      realease 模式下的 AndroidManifest.xml :

       1 <manifest xmlns:android="http://schemas.android.com/apk/res/android"
       2    package="com.dajiazhongyi.dajia.pedumodule">
       3 
       4    <application
       5        android:allowBackup="true"
       6        android:supportsRtl="true">
       7 
       8        <activity
       9            android:name="com.dajiazhongyi.dajia.pedumodule.ui.PEducationListActivity"
      10            android:screenOrientation="portrait"/>
      11 
      12        <activity
      13            android:name="com.dajiazhongyi.dajia.pedumodule.ui.syslib.SystemEduDetailListActivity"
      14            android:screenOrientation="portrait"/>
      15 
      16        <activity
      17            android:name="com.dajiazhongyi.dajia.pedumodule.ui.syslib.SystemEduListActivity"
      18            android:screenOrientation="portrait"/>
      19 
      20    </application>
      21 
      22 </manifest>

      三.模塊化分層設計

      合理的模塊化分層設計是非常重要的,就像一個房子一樣,合理的框架設計是成功的保證。
      模塊化分層設計需要達到以下幾個目標:

      1. 模塊職責明確;

      2. 模塊代碼邊界清晰;

      3. 模塊通信

      四.模塊職責明確

      根據職責進行分層設計是合理有效的,以下是在項目實踐中采用的分層設計。

      ①.SDK
      SDK層包括的內容如圖所示,需要強調的是并不是所有的第三方Libraries都放到SDK,必須是通用的基礎級別的。

      ②.組件庫
      我們將各個業務模塊公用的組件整合到組件庫中,組件庫并不一定是一個module,它也可以是多個module,實際使用的時候更多的被業務模塊依賴。

      ③.BaseCore
      這是最重要的一個層級,APP核心的部分就是它,BaseCore可以用通用的定義以下幾個部分:

      CoreAccount: APP賬號管理,賬號登錄、注銷、Profile信息獲取等;
      CoreNetwork: 以Retrofit2為例,CoreNetwork并不提供業務模塊的API,只是提供基礎的網絡狀態管理、網絡錯誤管理;
      CoreStorage: 處理SQLite、Preferences;
      CoreCommunication:模塊之間的通信主要有三種:事件通知、頁面跳轉(Activity、Service)、接口調用。模塊通信是最重要的層次,后面會重點講

      此外,這個層次是最容易代碼越界的層次,隨著業務的不斷復雜,業務模塊中的代碼是極有可能下沉到BaseCore的,從而導致Core層代碼越來越冗余。清晰合理的代碼邊界規范是重要的。

      ④業務模塊
      業務模塊的拆分粒度需要把控,太小的粒度并不是很合理。其中App(Release)是最終發布出去的版本,它是對其他模塊1…N 的整合。各個業務模塊在debug’階段,可以獨立打包成apk進行調試,在release階段,則作為APP的module被引用。各個業務模塊之間不進行相互調用,它們之間的通信通過BaseCore層來實現。

      五.代碼邊界

      合理的代碼邊界約定可以保證層次的清晰、避免架構變得冗余,雖然沒法完全保證,畢竟定期的重構是無法避免的。

      ①各個業務模塊之間無依賴關系,模塊之間頁面的跳轉通過ARouter等頁面路由協議進行;

      ②模塊之間的事件通信采用EventBus,并依賴于BaseCore層的事件Manager進行管理;

      ③模塊之間的功能暴露全部通過接口,接口需要下沉到BaseCore層,接口使用前必須先注冊,調用方式形如下,后續文章會詳細介紹:

      ServiceManager.regist(PluginService.class); 
      ServiceManager.get(PluginService.class).execute();

      ④組件庫組件必須提供個性化定制,方便業務模塊使用;

      ⑤合理控制各組件和各業務模塊的拆分粒度,太小的公有模塊不足以構成單獨組件或者模塊的,我們先放到類似于 CommonModule 的組件中,在后期不斷的重構迭代中視情況進行進一步的拆分;

      ⑥上層的公有業務或者功能模塊可以逐步下放到下層,下放過程中按照層次職責歸類下放;

      ⑦各個模塊之間的橫向依賴關系,比如在使用PluginService2之前,需要先注冊PluginService1,這種依賴管理后續會詳細介紹

       

      六.模塊通信

      模塊通信需要解決三大問題:

      1. 頁面跳轉

      2. 事件通知

      3. 接口調用

      頁面跳轉

      這里介紹一款頁面路由神器:ARouter https://github.com/alibaba/ARouter

      本著能用、夠用、好用的原則,這款神器支持以下功能:

      1. 支持直接解析標準URL進行跳轉,并自動注入參數到目標頁面中
      2. 支持多模塊工程使用
      3. 支持添加多個攔截器,自定義攔截順序
      4. 支持依賴注入,可單獨作為依賴注入框架使用
      5. 支持InstantRun
      6. 支持MultiDex(Google方案)
      7. 映射關系按組分類、多級管理,按需初始化
      8. 支持用戶指定全局降級與局部降級策略
      9. 頁面、攔截器、服務等組件均自動注冊到框架
      10. 支持多種方式配置轉場動畫
      11. 支持獲取Fragment
      12. 完全支持Kotlin以及混編(配置見文末 其他#5)

      其調用方式如下:

      1. 添加注解
      @Route(path = "/test/activity")
      public class YourActivity extend Activity {
         ...
      }
      
      2. 初始化SDK
      if (isDebug()) {           // 這兩行必須寫在init之前,否則這些配置在init過程中將無效
         ARouter.openLog();     // 打印日志
         ARouter.openDebug();   // 開啟調試模式(如果在InstantRun模式下運行,必須開啟調試模式!線上版本需要關閉,否則有安全風險)
      }
      ARouter.init(mApplication); // 盡可能早,推薦在Application中初始化
      
      3. 發起路由操作
      // 1\. 應用內簡單的跳轉(通過URL跳轉在'進階用法'中)
      ARouter.getInstance().build("/test/activity").navigation();
      
      // 2\. 跳轉并攜帶參數
      ARouter.getInstance().build("/test/1")
        .withLong("key1", 666L)
        .withString("key3", "888")
        .withObject("key4", new Test("Jack", "Rose"))
        .navigation();

      實際應用中,在BaseCore中實現一個RouterManager,管理路由初始化,跳轉等事宜:

      public class RouterManager {
      
         /**
          * Router Path
          */
         public static final String URL_WELCOME = "/loginModule/welcome";
         public static final String URL_LOGIN = "/loginModule/login";
      
         public static final String URL_MAIN_LOGIN = "/loginModule/main";
         public static final String URL_MAIN_PEDU = "/peduModule/main";
      
         ...
      
         /**
          * Module application name
          */
         public static final String MODULE_LOGIN = "loginmodule";
         public static final String MODULE_PEDU = "pedumodule";
      
         public static void initRouter(Application application) {
             if (BuildConfig.DEBUG) {
                 ARouter.openLog();     // 打印日志
                 ARouter.openDebug();   // 開啟調試模式(如果在InstantRun模式下運行,必須開啟調試模式!線上版本需要關閉,否則有安全風險)
             }
             ARouter.init(application);
         }
      
         public static void gotoNewPage(Context context, String pageUrl) {
             ARouter.getInstance().build(pageUrl).navigation();
         }
      
         public static void goWelcome(Context context) {
             ARouter.getInstance().build(URL_WELCOME).navigation();
         }
      
         public static void goLogin(Context context) {
             ARouter.getInstance().build(URL_LOGIN).navigation();
         }
      
         public static void goHome(Context context) {
             String packageName = context.getApplicationInfo().packageName;
             LogUtils.logD(packageName);
             String suffix = packageName.substring(packageName.lastIndexOf(".") + 1);
             switch (suffix) {
                 case MODULE_LOGIN:
                     ARouter.getInstance().build(URL_MAIN_LOGIN).navigation();
                     break;
                 case MODULE_PEDU:
                     ARouter.getInstance().build(URL_MAIN_PEDU).navigation();
                     break;
             }
         }
      
         ...
      }

      更多使用方法可以參考github該庫的詳細介紹

      由于篇幅原因,事件通知、接口調用將在后續文章中介紹!!

      其他問題

      資源名沖突

      對于多個 Bussines Module 中資源名沖突的問題,可以通過在 build.gradle 定義前綴的方式解決:

      defaultConfig {
        ...
        resourcePrefix "module_name_"
        ...
      }

      而對于 Module 中有些資源不想被外部訪問的,我們可以創建 res/values/public.xml,添加到 public.xml 中的 resource 則可被外部訪問,未添加的則視為私有:

      <resources>
         <public name="module1_str" type="string"/>
      </resources>

       

      posted on 2018-08-17 15:08  安卓筆記俠  閱讀(1556)  評論(0)    收藏  舉報

      主站蜘蛛池模板: 久女女热精品视频在线观看| 中文字幕国产精品综合| 99人体免费视频| 保定市| 亚洲国产欧美日韩欧美特级| 一区二区福利在线视频| 中文字幕国产日韩精品| 一区二区三区无码免费看| 成年在线观看免费人视频| 五月综合网亚洲乱妇久久| 久色伊人激情文学你懂的| 亚洲欧美人成电影在线观看| 久久人人爽人人爽人人av| 99riav精品免费视频观看| 麻豆国产成人AV在线播放| 久久久久无码精品亚洲日韩 | 久久精品国产99麻豆蜜月| 少妇特黄a一区二区三区| 性欧美三级在线观看| 亚洲av激情一区二区三区| 亚洲人成网站观看在线观看| 成人性无码专区免费视频| 人妻中文字幕精品一页| 久久91精品牛牛| 一区二区在线观看 激情| 亚洲欧美高清在线精品一区二区| 我国产码在线观看av哈哈哈网站| 国产怡春院无码一区二区| 亚洲精品成人片在线观看精品字幕 | 熟女人妻aⅴ一区二区三区电影| 久久99九九精品久久久久蜜桃| 成人无遮挡裸免费视频在线观看| 亚洲国产成人综合自在线| 91中文字幕一区在线| 99久久er热在这里只有精品99| 欧美黑人巨大xxxxx| 制服丝袜国产精品| 精品精品亚洲高清a毛片| 成人片黄网站色大片免费毛片| 国产精品亚洲中文字幕| 国产无码高清视频不卡|