日日操夜夜添-日日操影院-日日草夜夜操-日日干干-精品一区二区三区波多野结衣-精品一区二区三区高清免费不卡

公告:魔扣目錄網為廣大站長提供免費收錄網站服務,提交前請做好本站友鏈:【 網站目錄:http://www.ylptlb.cn 】, 免友鏈快審服務(50元/站),

點擊這里在線咨詢客服
新站提交
  • 網站:51998
  • 待審:31
  • 小程序:12
  • 文章:1030137
  • 會員:747

作者:popular_linda

鏈接:https://juejin.im/post/5eb019b8e51d45338806f2c0

 

什么是組件

項目按功能拆分成功若干個組件,每個組件負責相應的功能,如login、pay、live。組件化與模塊化類似,但不同的是模塊化是以業務為導向,組件化是以功能為導向。組件化的顆粒度更細,一個模塊里可能包含多個組件。實際開發中一般是模塊化與組件化相結合的方式。

 

為什么要組件

(1)提高復用性避免重復造輪子,不同的項目可以共用同一組件,提高開發效率,降低維護成本。

(2)項目按功能拆分成組件,組件之間做到低耦合、高內聚,有利于代碼維護,某個組件需要改動,不會影響到其他組件。

組件化方案

組件化是一種思想,團隊在使用組件化的過程中不必拘泥于形式,可以根據自己負責的項目大小和業務需求的需要制定合適的方案,如下圖就是一種組件化結構設計。

Android組件化開發思想與實踐
  • 宿主App

    在組件化中,app可以認為是一個入口,一個宿主空殼,負責生成app和加載初始化操作。

  • 業務層

    每個模塊代表了一個業務,模塊之間相互隔離解耦,方便維護和復用。

  • 公共層

    既然是base,顧名思義,這里面包含了公共的類庫。如Basexxx、Arouter、ButterKnife、工具類等

  • 基礎層

    提供基礎服務功能,如圖片加載、網絡、數據庫、視頻播放、直播等。

注:以上結構只是示例,其中層級的劃分和層級命名并不是定性的,只為更好的理解組件化。

組件化面臨的五問題

 

一,跳轉和路由

Activity跳轉分為顯示和隱示:

//顯示跳轉Intent intent = new Intent(cotext,LoginActivity.class);startActvity(intent)

 
//隱示跳轉Intent intent = new Intent;intent.setClassName("app包名" , "activity路徑");intent.setComponent(new Component(new Component("app報名" , "activity路徑")));startActivity(intent);
 

1、顯示跳轉,直接依賴,不符合組件化解耦隔離的要求。

2、對于隱示跳轉,如果移除B的話,那么在A進行跳轉時就會出現異常崩潰,我們通過下面的方式來進行安全處理

//隱示跳轉Intent intent = new Intent;intent.setClassName("app包名" , "activity路徑");intent.setComponent(new Component(new Component("app報名" , "activity路徑")));if (intent.resolveActivity(getPackageManager) != ) { startActivity(intent);}startActivity(intent);

原生推薦使用隱示跳轉,不過在組件化項目中,為了更優雅的實現組件間的頁面跳轉可以結合路由神器ARouter,ARouter類似中轉站通過索引的方式無需依賴,達到了組件間解耦的目的。

Aouter使用方式如下:

1、因為ARouter是所有模塊層組件都會用到所以我們可以在Base中引入

api 'com.alibaba:arouter-api:1.5.0'annotationProcessor 'com.alibaba:arouter-compiler:1.2.2'

2、在每個子module里添加

Android { defaultConfig { ... JAVACompileOptions { annotationProcessorOptions { arguments = [AROUTER_MODULE_NAME: project.getName()] } } }}

annotationProcessor會通過javaCompileOptions這個配置來獲取當前module的名字。

3、在Appliction里對ARouter進行初始化,因為ARouter是所有的模塊層組件都會用到,所以它的初始化放在BaseAppliction中完成。

public class BaseApplication extends Application { @Override public void onCreate { super.onCreate; initRouter(this); }
 public void initRouter(Application application) { if (BuildConfig.DEBUG) { // 這兩行必須寫在init之前,否則這些配置在init過程中將無效 ARouter.openLog; //打印日志 ARouter.openDebug; // 開啟調試模式(如果在InstantRun模式下運行,必須開啟調試模式!線上版本需要關閉,否則有安全風險) } ARouter.init(application); //盡可能早,推薦在Application中初始化 }}

4、在Activity中添加注解Route

public interface RouterPaths { String LOGIN_ACTIVITY = "/login/login_activity";}
// 在支持路由的頁面上添加注解(必選)// 這里的路徑需要注意的是至少需要有兩級,/xx/xx@Route(path = RouterPaths.LOGIN_ACTIVITY)public class LoginActivity extends BaseActivity {}

path是指跳轉路徑,要求至少兩級,即/xx/xx的形式,第一個xx是指group,如果不同module中出現相同的group會報錯,所以建議group用module名稱標識。

5、發起跳轉操作

ARouter.getInstance.build(RouterPaths. LOGIN_ACTIVITY).navigation;

ARouter的還有很多其他功能,這里不作詳細說明。

 

二,Aplication動態加載

Application作為程序的入口通常做一些初始化,如上面提到的ARouter,由于ARouter是所有模塊層組件都要用到,所以把它放在BaseApplication進行初始化。如果某個初始化操作只屬于某個模塊,為了降低耦合,我們應該把該初始化操作放在對應模塊module的Application里。如下:

1、在BaseModule定義接口

public interface BaseApplicationImpl { void init; ...}

2、在ModuleConfig中進行配置

public interface ModuleConfig { String LOGIN = "com.linda.login.LoginApplication"; String DETAIL = "com.linda.detail.DetailApplication"; String PAY = "com.linda.pay.PayApplication";
 String modules = { LOGIN, DETAIL, PAY };}

3、在BaseApplicatiion通過反射的方式獲取各個module中Application的實例并調用init方法。

public abstract class BaseApplication extends Application implements BaseApplicationImpl { @Override public void onCreate { super.onCreate; initComponent; initARouter; }
 /** * 初始化各組件 */ public void initComponent { for (String module : ModuleConfig.modules) { try { Class clazz = Class.forName(module); BaseApplicationImpl baseApplication = (BaseApplicationImpl) clazz.newInstance; baseApplication.init; } catch (ClassNotFoundException e) { e.printStackTrace; } catch (IllegalAccessException e) { e.printStackTrace; } catch (InstantiationException e) { e.printStackTrace; } } } ...}

4、子module中實現init方法,并進行相關初始化操作

public class LiveApplication extends BaseApplication { public void init { //在這里做一些的Live相關的初始化操作 }}

 

三,模塊間通信

BroadcastReceiver:系統提供,比較笨重,使用不夠優雅。

EventBus:使用簡單優雅,將發送這與接收者解耦,2.x使用反射方式比較耗性能,3.x使用注解方式比反射快得多。

但是有些情況是BroadcastReceiver、EventBus解決不了的,例如想在detail模塊中獲取mine模塊中的數據。因為detail和mine都依賴了base,所以我們可以借助base來實現。

1、在base中定義接口并繼承ARouter的IProvider。

public interface IMineDataProvider extends IProvider { String getMineData;}

2、在mine模塊中新建MineDataProvider類實現IMineDataProvider,并實現getMineData方法

@Route(path = RouterPaths.MINE_DATA_PROVIDER)public class MineDataProvider implements IMineDataProvider { @Override public String getMineData { return "***已獲取到mine模塊中的數據***"; }
 @Override public void init(Context context) { }}

3、在detail中獲取MineDataProvider實例并調用IMineDataProvider接口中定義的方法

 IMineDataProvider mineDataProvider = (IMineDataProvider) ARouter.getInstance.build(RouterPaths.MINE_DATA_PROVIDER).navigation;if (mineDataProvider != ) { mGetMineData.setText(mineDataProvider.getMineData);}

 

四,資源沖突

組件化項目中有很多個module,這就難免會出現module中資源命名相同而引起引用錯誤的情況。為此我們可以在每個module的build.gradle文件進行如下配置(例如login模塊)。

resourcePrefix "login_"

所有的資源必須以指定的字符串(建議module名稱)做前綴,不然會報錯。不過這種方式只限定與xml文件,對圖片資源無效,圖片資源仍需要手動修改。

//布局文件命名示例login_activity_login.xml
<resources> <!--字符串資源命名示例--> <string name="login_app_name">Login</string></resources>

 

五,單個組件運行調試

當項目越來越龐大時,編譯或運行一次就需要花費很長時間,而組件化可以通過配置對每個模塊進行單獨調試,大大提高了開發效率。我們需要對每個module進行如下配置:

1、在項目根目錄新建common_config.gradle文件并聲明變量isModuleDebug;

project.ext { //是否允許module單獨調試 isModuleDebug = false}

2、引入common_config配置,另外因為組件化中每個module都是一個library,如要單獨運行調試需要將library換成application,在module的build.gradle中文件中做如下修改:

//引入common_config配置apply from: "${rootProject.rootDir}/common_config.gradle"
if (project.ext.isModuleDebug.toBoolean) { apply plugin: 'com.android.application'} else { apply plugin: 'com.android.library'}
android { defaultConfig { if (project.ext.isModuleDebug.toBoolean) { // 單獨調試時需要添加 applicationId applicationId "com.linda.login" } ... } sourceSets { main { //在需要單獨調試的module的src/main目錄下新建manifest目錄和AndroidManifest文件 // 單獨調試與集成調試時使用不同的 AndroidManifest.xml 文件 if (project.ext.isModuleDebug.toBoolean) { manifest.srcFile 'src/main/manifest/AndroidManifest.xml' } else { manifest.srcFile 'src/main/AndroidManifest.xml' } } }}

關于兩個清單文件的不同之處如下:

<!--單獨調試--><manifest xmlns:android="http://schemas.android.com/apk/res/android" package="com.linda.login"> <application android:allowBackup="true" android:icon="@drawable/ic_launcher" android:label="@string/login_app_name" android:supportsRtl="true" android:theme="@style/base_AppTheme"> <activity android:name=".ui.LoginActivity"> <intent-filter> <action android:name="android.intent.action.MAIN" /> <category android:name="android.intent.category.LAUNCHER" /> </intent-filter> </activity> </application></manifest>
<!-- 集成調試--><manifest xmlns:android="http://schemas.android.com/apk/res/android" package="com.linda.login"> <application android:allowBackup="true" android:label="@string/login_app_name" android:supportsRtl="true" android:theme="@style/base_AppTheme"> <activity android:name=".ui.LoginActivity" /> </application></manifest>

3、如果module單獨調試,那么在app就不能再依賴此module,因為此時app和module都是project,project之間不能相互依賴,在app的build.gradle文件中做如下修改

dependencies { if (!project.ext.isModuleDebug) { implementation project(path: ':detail') implementation project(path: ':login') implementation project(path: ':pay') } implementation project(path: ':main') implementation project(path: ':home') implementation project(path: ':mine')}

4、最后將isModuleDebug改為true,然后編譯,便可以看到login、detail、pay模塊可以獨立運行調試了。

Android組件化開發思想與實踐Android組件化開發思想與實踐

組件化Demo地址:https://github.com/zhoulinda/ComponentDemo

  • 10個讓你用了大呼 “我*NB” 的網站

  • Android面經分享,失業兩個月,五一節前拿到offer

  • 7 款 mac 工具,提高你的效率!

你了解多少組件化呢?

分享到:
標簽:Android
用戶無頭像

網友整理

注冊時間:

網站:5 個   小程序:0 個  文章:12 篇

  • 51998

    網站

  • 12

    小程序

  • 1030137

    文章

  • 747

    會員

趕快注冊賬號,推廣您的網站吧!
最新入駐小程序

數獨大挑戰2018-06-03

數獨一種數學游戲,玩家需要根據9

答題星2018-06-03

您可以通過答題星輕松地創建試卷

全階人生考試2018-06-03

各種考試題,題庫,初中,高中,大學四六

運動步數有氧達人2018-06-03

記錄運動步數,積累氧氣值。還可偷

每日養生app2018-06-03

每日養生,天天健康

體育訓練成績評定2018-06-03

通用課目體育訓練成績評定