阿里ARouter路由實現Android模組化開發
概述
從 2016 年開始,模組化在 Android 社群越來越多的被提及。隨著移動平臺的不斷髮展,移動平臺上的軟體慢慢走向複雜化,體積也變得臃腫龐大,為了降低大型軟體複雜性和耦合度,同時也為了適應模組重用、多團隊並行開發測試等等需求,模組化在 Android 平臺上變得勢在必行。阿里 Android 團隊在年初開源了他們的容器化框架 Atlas 就很大程度說明了當前 Android 平臺開發大型商業專案所面臨的問題。
那麼什麼是模組化呢,和我們常說的元件化又有什麼聯絡和區別呢?根據《 Java 應用架構設計:模組化模式與 OSGi 》一書中對模組化的定義:模組化是一種處理複雜系統分解為更好的可管理模組的方式。對於這種概念性的解釋,太過生澀難懂,不夠直觀。
那麼究竟何為模組化呢?舉個例子,相信隨著業務的不斷迭代,APK專案已經無限大了,以我們公司的電商專案為例,在迭代了5年後,apk的體積已經40M+,如果使用傳統的ant打包大概差不多要近10分鐘,如果用增量打包時間也要3-5分鐘。但是可以發現,很多老的程式碼其實我們在最新的版本是不需要的,當然我們可以手動的將這些程式碼刪除,但是又還怕啥時候用到。此時,最好的方法就是將這些模組獨立成一個獨立的工程,當需要的時候再引入進來,這就是模組化的一個背景。
所以,此處,我們對模組化和元件化做一個簡單的定義:
模組化:指解決一個複雜問題時自頂向下逐層把系統劃分成若干模組的過程,如訂單模組(OrderModule)、特賣模組(SPecialModule)、即時通訊模組(InstantMessagingModule)等等。
元件化:元件是指通用的功能或者UI庫可以做成一個功能元件,如地圖元件(MapSDK)、支付元件(AnjukePay)、路由元件(Router)等等;
外掛化:和模組化差不多,只是它是可以把模組打包成獨立的apk,可以動態的載入,刪除,獨立的外掛apk可以線上下載安裝,有利於減少apk的體積和實現模組的熱修復。目前熱門的外掛化方案有:阿里的atlas,360公司的RePlugin,滴滴的VirtualAPK等等;
例如,下面是模組化之前和模組化之後的專案的目錄結構:
模組化的示意圖可以用下面的模型表示:
模組化要解決的問題
要使用模組化開發Android專案,有以下幾點需要注意:
- 模組間頁面跳轉(路由);
- 模組間事件通訊;
- 模組間服務呼叫;
- 模組的獨立執行;
- 其他注意事項;
為了方便講解,我們以下面的專案為例:
這是一個常見的首頁畫面,該頁面主要有首頁、微聊、推薦和我的組成。我們將該4個Tab單獨成4個獨立的模組。
其中:
- app模組:主模組,主要進行搭載各個模組的功能;
- lib_base:對ARouter進行初始化,和放置一些各個模組公用的封裝類;
- module_home,module_caht,module_recom,module_me:分別對應“首頁”、“微聊”、“推薦”、“我的”模組。
ARouter模組化開發
ARouter各個模組的gradle配置
app模組是程式的容器,起到程式入口的作用,lib_base作為基礎模組,用來將一些公共的庫和對ARouter的初始化操作放在這一模組中。因此每個子模組都會用到它裡面的內容,所以我們在 lib_base中新增如下內容。
compile 'com.alibaba:arouter-api:1.2.4'
annotationProcessor "com.alibaba:arouter-compiler:1.1.4"
compile 'com.android.support:design:27.1.1'
compile 'org.simple:androideventbus:1.0.5.1'
compile 'com.alibaba:fastjson:1.2.31'
因為我們把攔截器等公用類放在base註冊,在編譯期間生成路徑對映。所以還需要在build中加入如下配置:
defaultConfig {
javaCompileOptions {
annotationProcessorOptions {
arguments = [moduleName: project.getName()]
}
}
}
由於每個子模組都會用到lib_base裡面的東西,所以需要在各子模組的build檔案中匯入(即module_home,module_caht,module_recom,module_me等模組中)如下配置:
//注意,此處也需要引入了com.alibaba:arouter-compiler:1.1.4
annotationProcessor 'com.alibaba:arouter-compiler:1.1.4'
compile project(':lib_base')
同樣,也需要在各子模組的build中加入如下配置。
defaultConfig {
javaCompileOptions {
annotationProcessorOptions {
arguments = [moduleName: project.getName()]
}
}
}
然後在app模組(也即是主模組)對各個子模組進行依賴。
compile project(':module_home')
compile project(':module_chat')
compile project(':module_recom')
compile project(':module_me')
子模組依賴規則配置
對於模組化專案,每個單獨的Module 都可以單獨編譯成 APK。在開發階段需要單獨打包編譯,專案釋出的時候又需要它作為專案的一個 Module 來整體編譯打包。簡單的說就是開發時是 Application,釋出時是 Library。所以,需要在子模組中做如下的配置:
if(isBuildModule.toBoolean()){
apply plugin: 'com.android.application'
}else{
apply plugin: 'com.android.library'
}
同理,Manifest.xml 也需要有兩套:
if (isBuildModule.toBoolean()) {
manifest.srcFile 'src/main/debug/AndroidManifest.xml'
} else {
manifest.srcFile 'src/main/release/AndroidManifest.xml'
}
同時,每個子模組的defaultConfig還需要增加如下配置:
defaultConfig {
if (!isNeedMeModule.toBoolean()) {
applicationId "com.xzh.module_me"
}
}
而上面的isBuildModule.toBoolean()判斷條件,讀取的是專案根目錄下的gradle.properties配置檔案。
# 是否需要單獨編譯 true表示需要,false表示不需要
isNeedHomeModule=false
#isNeedHomeModule=true
isNeedChatModule=false
#isNeedChatModule=false
isNeedRecomModule=false
#isNeedRecomModule=false
isNeedMeModule=false
#isNeedMeModule=false
然後根據上面的編譯配置在app模組中新增如下依賴:
if (!isNeedHomeModule.toBoolean()) {
compile project(':module_home')
}
if (!isNeedChatModule.toBoolean()) {
compile project(':module_chat')
}
if (!isNeedRecomModule.toBoolean()) {
compile project(':module_recom')
}
if (!isNeedMeModule.toBoolean()) {
compile project(':module_me')
}
如果需要單獨執行某個模組時,只需要修改gradle.properties對應的配置即可。例如,需要單獨執行module_home模組時,只需要開啟對於的配置即可isNeedHomeModule=true。
配置注意
由於配置後項目只有一個入口和啟動檔案(即app模組的MainActvity),所以其他子模組的MainActivity的intent-filter攔截要去掉,不然會有多個桌面入口。
<activity android:name=".MainActivity">
<!--<intent-filter>-->
<!--<action android:name="android.intent.action.MAIN" />-->
<!--<category android:name="android.intent.category.LAUNCHER" />-->
<!--</intent-filter>-->
</activity>
ARouter使用
以上面的效果實現為例,在MainActivity中使用TabLayout+Adapter的形式搭建4個Tab頁面。程式碼如下:
public class MainActivity extends AppCompatActivity {
private ViewPager mMViewPager;
private TabLayout mToolbarTab;
private int[] tabIcons = {
R.drawable.tab_home,
R.drawable.tab_weichat,
R.drawable.tab_recommend,
R.drawable.tab_user
};
private String[] tab_array;
private DemandAdapter mDemandAdapter;
private List<Fragment> fragments = new ArrayList<>();
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
init();
}
private void init() {
initData();
initView();
setViewPagerAdapter();
setTabBindViewPager();
setItem();
}
private void initData() {
tab_array = getResources().getStringArray(R.array.tab_main);
fragments.clear();
fragments.add(FragmentUtils.getHomeFragment());
fragments.add(FragmentUtils.getChatFragment());
fragments.add(FragmentUtils.getRecomFragment());
fragments.add(FragmentUtils.getMeFragment());
}
private void initView() {
mMViewPager = (ViewPager) findViewById(R.id.mViewPager);
mToolbarTab = (TabLayout) findViewById(R.id.toolbar_tab);
}
private void setViewPagerAdapter() {
mDemandAdapter = new DemandAdapter(getSupportFragmentManager(),fragments);
mMViewPager.setAdapter(mDemandAdapter);
}
private void setTabBindViewPager() {
mToolbarTab.setupWithViewPager(mMViewPager);
}
private void setItem() {
for (int i = 0; i < mToolbarTab.getTabCount(); i++) {
mToolbarTab.getTabAt(i).setCustomView(getTabView(i));
}
}
public View getTabView(int position) {
View view = LayoutInflater.from(this).inflate(R.layout.item_tab, null);
ImageView tab_image = view.findViewById(R.id.tab_image);
TextView tab_text = view.findViewById(R.id.tab_text);
tab_image.setImageResource(tabIcons[position]);
tab_text.setText(tab_array[position]);
return view;
}
}
然後,使用ARouter來獲取到各個模組的Fragment。
public class FragmentUtils {
public static Fragment getHomeFragment() {
Fragment fragment = (Fragment) ARouter.getInstance().build(RouteUtils.Home_Fragment_Main).navigation();
return fragment;
}
public static Fragment getChatFragment() {
Fragment fragment = (Fragment) ARouter.getInstance().build(RouteUtils.Chat_Fragment_Main).navigation();
return fragment;
}
public static Fragment getRecomFragment() {
Fragment fragment = (Fragment) ARouter.getInstance().build(RouteUtils.Recom_Fragment_Main).navigation();
return fragment;
}
public static Fragment getMeFragment() {
Fragment fragment = (Fragment) ARouter.getInstance().build(RouteUtils.Me_Fragment_Main).navigation();
return fragment;
}
}
而FragmentUtils使用了RouteUtils來定義具體的跳轉協議。
public class RouteUtils {
public static final String Home_Fragment_Main = "/home/main";
public static final String Chat_Fragment_Main = "/chat/main";
public static final String Recom_Fragment_Main = "/recom/main";
public static final String Me_Fragment_Main = "/me/main";
}
上面的子模組使用的是Fragment,所以,在子模組中要使用Route說明。例如:
@Route(path = RouteUtils.Chat_Fragment_Main)
public class MainFragment extends Fragment {
@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle
savedInstanceState) {
View view = inflater.inflate(R.layout.fragment_weichat, null);
return view;
}
@Override
public void onDestroyView() {
super.onDestroyView();
}
}
跨模組跳轉
假如要實現跨模組跳轉,首先在RouteUtils定義
public static final String Me_Login = "/me/main/login";
ARouter要跳轉Activity,就在這個Activity上加入註解。
@Route(path = RouteUtils.Me_Login)
public class LoginActivity extends AppCompatActivity{
}
然後在需要跳轉的地方新增如下程式碼:
ARouter.getInstance().build(RouteUtils.Me_Login).navigation();
實現ForResult返回資料
如果跨模組跳轉需要返回資料,即Activity的StartActivityForResult,則可以使用下面的方式。
ARouter.getInstance().build(RouteUtils.Chat_ForResult).navigation(this, 666); //666即為Code
接收資料資料:
@Override
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
super.onActivityResult(requestCode, resultCode, data);
switch (requestCode) {
case 666:
String name = data.getStringExtra("name");
UIUtils.showToast(name + ",resultCode===>" + resultCode);
break;
default:
break;
}
}
然後,接受返回資料:
Intent intent = new Intent();
intent.putExtra("name", "ForResult返回的資料");
setResult(999, intent);
finish();
使用Eventbus跨模組通訊
使用Eventbus進行跨模組通訊,首先在需要接受的地方定義一個訂閱者。
@Subscriber(tag = EvenBusTag.GOTO_EVENTBUS)
public void onEvent(String s) {
UIUtils.showToast(s);
}
然後在傳送方使用EventBus傳送訊息。例如:
@Route(path = RouteUtils.Me_EventBus)
public class EventBusActivity extends AppCompatActivity implements View.OnClickListener {
/**
* eventBus資料接收頁面
*/
private TextView mTextView;
/**
* eventBus返回資料
*/
private Button mBtnBackData;
private String name;
private long age;
private EventBusBean eventbus;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_event_bus);
ARouter.getInstance().inject(this);
initData();
initView();
}
private void initData() {
name = getIntent().getStringExtra("name");
age = getIntent().getLongExtra("age", 0);
eventbus = getIntent().getParcelableExtra("eventbus");
}
private void initView() {
mTextView = (TextView) findViewById(R.id.textView);
mBtnBackData = (Button) findViewById(R.id.btn_back_data);
mBtnBackData.setOnClickListener(this);
mTextView.setText("name=" + name + ",\tage=" + age + ",\tproject=" + eventbus.getProject() +
",\tnum=" + eventbus.getNum());
}
@Override
public void onClick(View v) {
int i = v.getId();
if (i == R.id.btn_back_data) {
EventBus.getDefault().post(name, EvenBusTag.GOTO_EVENTBUS);
finish();
} else {
}
}
}
其實,ARouter的功能遠不止於此,後面將為大家一一講解,並最終自己實現一個模組間的路由。
相關推薦
阿里ARouter路由實現Android模組化開發
概述 從 2016 年開始,模組化在 Android 社群越來越多的被提及。隨著移動平臺的不斷髮展,移動平臺上的軟體慢慢走向複雜化,體積也變得臃腫龐大,為了降低大型軟體複雜性和耦合度,同時也為了適應模組重用、多團隊並行開發測試等等需求,模組化在 Android
使用阿里ARouter路由實現元件化(模組化)開發流程
Android平臺中對頁面、服務提供路由功能的中介軟體,我的目標是 —— 簡單且夠用。 這是阿里對Arouter的定位,那麼我們一起來梳理一下Arouter使用流程,和使用中我所遇到的一些問題! 先來看看有哪些功能 模組化的要解決的問題
Android模組化開發、元件化開發;
模組化開發:優點嘛,專案過大時便於管理; 1、在根目錄的gradle.properties檔案下新增 isBuildModule=false; 使用isBuildModule來控制這個是Library還是獨立的APP; 2、建立一個新的Module,在其build.gra
Android模組化開發遇到的問題: 資源名衝突的問題
方法一: 保護某些 resources 不被外部訪問,可以建立res/values/public.xml,因為 public 是關鍵詞,所以需要用 new file 的方式建立。至少新增一行,未新增的視為 private。(經驗證,好像沒有效果,知道的大神幫忙留言,最好
一點一點學maven(10)——eclipse實現maven模組化開發
1、新建父專案modules-container,選擇maven project,作為所有子模組的容器 2、新建子專案modules-demo01,選擇maven module,module name為子模組名,parent project選擇
模組化開發框架實現原理
本文是螞蟻金服微貸事業部自主研發的模組化開發框架TITAN的實現原理,該框架後續可能會開源,敬請期待! 需求背景 應用拆分的多或少都有問題。多則維護成本高,每次釋出一堆應用。少則拆分成本高,無用功能很難下線。 故障不隔離。當一個系統由多人同時參與開發時,修改A功能,可能會影響B功能,引發故障
android模組化app開發筆記-1環境搭建
由於專案做的越來越大,業務上就產生了要將app模組化的需求,所謂模組化就是將一個app分成不同功能的小模組(外掛),當安裝程式的時候並不需要將所有模組一次全部安裝,使用者可以在需要的時候視情況從伺服器上更新新增小外掛。 android上模組化一直都有人在摸索也出現
android模組化app開發筆記-2外掛間佈局檔案共享
android程式設計時佈局檔案,圖片資源等都是放在同一個資料夾下,這樣照成一個問題就是我們想重用UI佈局檔案和圖片時就還需要其分離這些資料,相信大部分android程式設計師都遇到過這樣的問題,其痛苦程度不亞於世紀末日趕不上諾亞方舟。 今天我用apkplug框
阿里再開源!模組化開發框架JarsLink
JarsLink (原名Titan) 是一個基於JAVA的模組化開發框架,它提供在執行時動態載入模組(一個JAR包)、解除安裝模組和模組間呼叫的API。也是阿里巴巴的開源專案之一 https://github.com/alibaba/jarslink,目前在微貸事業群廣泛使用。 需求背景 應
通過Gradle自動實現Android元件化模組構建
為什麼我們要用Gradle管理元件呢? 先來看看Android元件化需要實現的目標 按照業務邏輯劃分模組 專案模組能夠單獨啟動測試 能夠根據需求引入或刪除某些業務模組 通過不同模組的組合,組成不同的App 對於第一點:需要根據技術架構和業務架構來劃分模組,這裡
Android模組化和元件化開發簡單理解(一)
模組化和元件化可以理解為同一個概念: 將一個app分成多個模組,每個模組都是一個元件(module),開發過程中讓這些元件相互依賴或者單獨除錯某個元件。在釋出的時候將這些元件合併成一個apk。 Android元件化我的理解是 application與library之間相互
BaseAdapter的封裝來實現模組化開發
引子 要在一個手掌大的手機上展示各種豐富的資訊,橫向滑動與上下滑動已經成為了手機應用不可缺少的一部分。對於上下滑動,有一個被小看的神器ListView配合Adapter。為什麼被小看了呢?對比ScrollView來說,ListView不僅能夠實現不同介面的
使用DroidPlugin實現模組化開發(主要說呼叫)
github地址:https://github.com/DroidPluginTeam/DroidPlugin/blob/master/readme_cn.md 關於配置,跟著說明文件配置吧。 關於跳轉呼叫, 使用new Intent(String ActiviyUrl),你會發現,
Android 專案模組化開發,提高開發效率。
把Demo放在第一!!! 隨著需求的增加,程式碼量隨之變得龐大、臃腫。於是產生了很多影響開發效率的問題。 例如: 1. 方法數超過65K。 2. 程式編譯執行一次至少1-2分鐘。 3. 程式碼變得難以管理,影響閱讀及修改效
js-模組化開發總結
一.模組開發的概念 模組化開發是什麼:模組化開發是一種生產方式,這種方式生產效率高,維護成本低。從軟體開發的角度說,模組化開發是一種開發模式,寫程式碼的一種方式,開發效率高,維護成本低。 為什麼需要模組化開發:當一個專案開發的越來越複雜的時候,會遇到一些問題,比如命名衝突(重新命名),檔
模組化開發(requireJS)
模組化 在前端使用模組化開發,可以將程式碼根據功能實施模組的劃分,每個模組功能(職責)單一,在需要更改對應的功能的時候,只需要對指定的模組進行修改,其他模組不受任何影響。 為什麼要進行前端模組化? 達到公共模組的複用 可以很好的解決全域性變數汙染的問題 可以很好的解決各個功能之間的依賴關係
javascript 模組化開發
一、為什麼會有模組化 1. 當一個專案開發的越來越複雜的時候,會遇到一些問題,比如: 命名衝突:當專案由團隊進行協作開發的時候,不同開發人員的變數和函式命名可能相同;即使是一個開發,當開發週期比較長的時候,也有可能會忘記之前使用了什麼變數,從而導致重複命名,導致命
沒有前戲,簡明扼要的進入主題——什麼是模組化開發?
模組化開發,一個模組就是一個實現特定功能的檔案,有了模組我們就可以更方便的使用別人的程式碼,要用什麼功能就載入什麼模組。 模組化開發的4點好處: 1 避免變數汙染,命名衝突 2 提高程式碼複用率 3 提高維護性 4 依賴關係的管理
Android 模組化 元件化 外掛化的關係
模組化:一個程式按照其功能做拆分,分成相互獨立的模組(例如:登陸,註冊)。模組化的具體實施方法分為外掛化和元件化。 元件化:開發模式下面module本來就是一個獨立app,只是釋出模式下變成library。 外掛化:就是不存在釋出模式開發模式,每個元件業務就是一個獨立
初識模組化開發工具:
初識模組化開發工具:git 是分散式程式碼管理工具,管理程式碼的npm 是包管理工具,管理外掛、工具啊,是個轉換器,他是哪來的了,他是伴隨node下載下來的,版本也是伴隨node變化;node 是個後臺的環境;首先安裝node,然後用命令安裝browserify:npm install -g browseri