1. 程式人生 > >Android元件化 -- 完全解耦實踐方案

Android元件化 -- 完全解耦實踐方案

首先貼上原始碼地址,歡迎frok,歡迎start
原始碼地址

目前,Android 元件化普遍使用於移動開發,但是元件化的初衷是為了解耦程式碼,並行開發效率;小型app似乎會care不到,完全解耦的元件化會在app越來越臃腫的時候帶來很大的提升;

1.元件化介紹

ok,那麼我們需要知道完全解耦的元件化框架應該注意哪些點:

  1. 主app只加載業務元件,不可呼叫元件;元件與元件之間不存在呼叫關係;這樣無論是主app和業務元件都是完全獨立,完全解耦的;
  2. 主app和元件都依賴common元件,通過common的註冊和分發實現元件之間的互動,這個common我們姑且叫做業務主線
  3. android中page使用common下層介面和路由進行實現(在本框架中,ARouter實現Activity跳轉,ARouter-Interceptor實現Activity跳轉的攔截;Fragment通過common下沉註冊分發實現Fragment的填充)
  4. 每一個元件應當是一個app可單獨編譯:Library和Application之間轉化使用gradle配置相應的Manifest和applicationId

component.jpg

2.單獨編譯元件化配置(gradle)

zhujianmulu.png
依賴關係

  • App 依賴common
  • Home/Login/News 依賴common
  • common 依賴component-base

2.1. 首先在整個工程的gradle.properties中配置元件 Library/Application切換的開關:

isRunLogin = false  //login元件
isRunHome = false //home元件
isRunNews = false  //news元件

2.2. 由於android中Library(元件)/Application切換時的差異,需要單獨配置主見
以home元件為例:
首先開build.gradle:

//註釋1: 配置切換application/Library的打包
if (isRunHome.toBoolean()){
    apply plugin: 'com.android.application'
}else{
    apply plugin: 'com.android.library'
}

android {
    .......

    sourceSets {
       //註釋2: Library/Application切換  AndroidManifest  
main { if (isRunLogin.toBoolean()){ manifest.srcFile 'src/main/AndroidManifest.xml' }else{ manifest.srcFile 'src/main/manifest/AndroidManifest.xml' } } } ...... } ......
  • 註釋1: 切換application/Libaray的打包配置
  • 註釋2: Application為單獨編譯,需要有applicationId,並且主Activity需要配置main屬性;
    Libaray為整合編譯,元件不能有applicationId,且不可以設定啟動的main Activity
    下面看整合編譯(Library)和單獨編譯(Application)的Manifest配置:
    1.png
//整合編譯,打包為Library
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
    package="component.android.com.home">

    <application android:theme="@style/home_AppTheme">
        <activity android:name=".view.activity.HomeActivity"/>
    </application>

</manifest>

//單獨編譯,打包為單獨Application 可單獨編譯
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
    package="component.android.com.home">

    <application
        android:allowBackup="true"
        android:icon="@mipmap/ic_launcher"
        android:label="@string/app_name"
        android:name=".global.HomeApp"
        android:roundIcon="@mipmap/ic_launcher_round"
        android:supportsRtl="true"
        android:theme="@style/home_AppTheme">
        <activity android:name=".view.activity.HomeActivity">
            <intent-filter>
                <action android:name="android.intent.action.MAIN" />

                <category android:name="android.intent.category.LAUNCHER" />
            </intent-filter>
        </activity>
    </application>

</manifest>


3.元件之間activity跳轉(Actiivity跳轉)

3.1. 元件之間的activity跳轉,這裡使用ARouter

ARouter是阿里開源的一種頁面跳轉task

首先看ARouter在build.gralde的配置:

//主app build.gradle
......
dependencies {
    ......
    androidTestImplementation 'com.android.support.test:runner:1.0.2'
    androidTestImplementation 'com.android.support.test.espresso:espresso-core:3.0.2'
 
}
//home/login/news 元件  build.gradle
dependencies {
    ........
    annotationProcessor 'com.alibaba:arouter-compiler:1.1.4'
}

//common build.gradle

dependencies {
    ......
    api 'com.alibaba:arouter-api:1.3.1'
    // arouter-compiler 的註解依賴需要所有使用 ARouter 的 module 都新增依賴
    annotationProcessor 'com.alibaba:arouter-compiler:1.1.4'
}


3.2 在app和各元件中進行page跳轉

  • 首先是ARouter的初始化

public class MainApplication extends BaseApp {

    @Override
    public void onCreate() {
        super.onCreate();
        //在主app中初始化ARouter
        initRouter();
        initMoudleApp(this);
        initMoudleData(this);
    }

    private void initRouter() {
        if (BuildConfig.DEBUG){
            //列印日誌
            ARouter.openLog();
            ARouter.openDebug();
        }
        ARouter.init(this);
    }
    @Override
    public void initMoudleApp(Application application) {
        for (String moduleApp : AppConfig.moduleApps) {
            try {
                Class clazz = Class.forName(moduleApp);
                BaseApp baseApp = (BaseApp) clazz.newInstance();
                baseApp.initMoudleApp(this);
            } catch (ClassNotFoundException e) {
                e.printStackTrace();
            } catch (IllegalAccessException e) {
                e.printStackTrace();
            } catch (InstantiationException e) {
                e.printStackTrace();
            }
        }
    }

    @Override
    public void initMoudleData(Application application) {
        for (String moduleApp : AppConfig.moduleApps) {
            try {
                Class clazz = Class.forName(moduleApp);
                BaseApp baseApp = (BaseApp) clazz.newInstance();
                baseApp.initMoudleData(this);
            } catch (ClassNotFoundException e) {
                e.printStackTrace();
            } catch (IllegalAccessException e) {
                e.printStackTrace();
            } catch (InstantiationException e) {
                e.printStackTrace();
            }
        }
    }
}



//元件中  home--HomeApplication
public class HomeApp extends BaseApp {


    @Override
    public void initMoudleApp(Application application) {
        if (BuildConfig.DEBUG){
            //列印日誌
            ARouter.openLog();
            ARouter.openDebug();
        }
        ARouter.init(this);
    }

    @Override
    public void initMoudleData(Application application) {

    }
}

這裡需要注意一下 當整合編譯時候 ,元件僅僅是一個元件,不會單獨具備Applicagtion入口,所以需要在主app的MainApplication中利用反射的方式 initMoudleData/initMoudleData進行ARouter等初始化的配置;
下面看ARouter的跳轉例項:

//app/MainActivity
....
private void initClick() {
        findViewById(R.id.btn_nav_home).setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                ARouter.getInstance().build("/home/homeActivity").navigation()
          }
}

在app中實現跳轉,但是這個 path/home/homeActivity需要在home元件目標位置添加註解才能實現activity的跳轉:

@Route(path = "/myhome/homeActivity")
public class HomeActivity extends AppCompatActivity {

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_home);
    }
}

這樣 就成功實現類元件之間的activity的跳轉;

4.元件之間的邏輯互動

App點選跳轉home,須判斷登入邏輯:

  • 1.登入則跳轉home元件的homeActivity
  • 2.未登入則跳轉login元件的loginActivity,點選登入,再重複以上邏輯
    這樣 主app,home和login就實現了一個簡單的互動邏輯
    2.png
    首先開component:
//ILoginService
public interface ILoginService {
    boolean getLoginStatus();
    int getLoginUserId();
}
//DefultLoginService
public class DefultLoginService implements ILoginService {
    @Override
    public boolean getLoginStatus() {
        return false;
    }
    @Override
    public int getLoginUserId() {
        return 0;
    }
}
//ComponentServiceFactory
public class ComponentServiceFactory {

    ......

    public static ComponentServiceFactory getInstance(Context context){
        if (instance == null){
            synchronized (ComponentServiceFactory.class){
                if (instance == null){
                    instance = new ComponentServiceFactory();
                }
            }
        }
        return instance;
    }


    private ILoginService loginService;

    public void setLoginService(ILoginService iloginService){
        loginService = iloginService;
    }


    public ILoginService getLoginService(){
        if (loginService == null){
            loginService = new DefultLoginService();
        }
        return loginService;
    }

}


然後在login中通過common的ComponentServiceFactory註冊對應的loginService

//LoginService
public class LoginService implements ILoginService {
    @Override
    public boolean getLoginStatus() {
        return AccountUtils.getInstance().isAccountStatus();
    }

    @Override
    public int getLoginUserId() {
        return 0;
    }
}

//Login元件LoginApp註冊service
........
public class LoginApp extends BaseApp {

    @Override
    public void initMoudleApp(Application application) {
        Log.i("LoginApp","initMoudleApp");
        if (BuildConfig.DEBUG){
            //列印日誌
            ARouter.openLog();
            ARouter.openDebug();
        }
        ARouter.init(this);
        ComponentServiceFactory.getInstance(this).setLoginService(new LoginService());
    }

    @Override
    public void initMoudleData(Application application) {

    }
}

在App-MainActivity中跳轉homeActivity,在home元件中使用ARouter的攔截器:

//app-mainActivity
private void initClick() {
        findViewById(R.id.btn_nav_home).setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                ARouter.getInstance().build("/home/homeActivity").navigation(MainActivity.this, new NavCallback() {
                    //ARouter攔截器的監聽
                    @Override
                    public void onArrival(Postcard postcard) {
                        LogUtils.LogI("loginInterceptor","done");
                    }

                    @Override
                    public void onFound(Postcard postcard) {
                        //super.onFound(postcard);
                        LogUtils.LogI("loginInterceptor","found");
                    }

                    @Override
                    public void onLost(Postcard postcard) {
                        //super.onLost(postcard);
                        LogUtils.LogI("loginInterceptor","lost");
                    }

                    @Override
                    public void onInterrupt(Postcard postcard) {
                        //super.onInterrupt(postcard);
                        LogUtils.LogI("loginInterceptor","interrupt");
                    }
                });
            }
        });
    }


//home-HomeInterceptor
@Interceptor(priority = 1,name = "homeInterceptor")
public class HomeInterceptor implements IInterceptor {
    private Context context;

    @Override
    public void process(Postcard postcard, InterceptorCallback callback) {
        switch (postcard.getPath()){
            case "/myhome/homeActivity":
                //通過component進行邏輯互動
                if (ComponentServiceFactory.getInstance(context).getLoginService().getLoginStatus()){
                    callback.onContinue(postcard);
                }else {
                    ARouter.getInstance().build("/login/loginActivity").navigation();
                    //callback.onInterrupt(new RuntimeException("請登入"));
                    //callback.onContinue(postcard);
                }
                break;
            default:
                callback.onContinue(postcard);
                break;

        }
    }

    @Override
    public void init(Context context) {
        this.context = context;
    }
}

//login-loginInterceptor
@Interceptor(priority = 2,name = "loginInterceptor")
public class LoginInterceptor implements IInterceptor {
    private Context context;

    @Override
    public void process(Postcard postcard, InterceptorCallback callback) {
        switch (postcard.getPath()){
            case "/login/loginActivity":
                LogUtils.LogI("loginInterceptor","請點選登入按鈕");
                callback.onContinue(postcard);
                break;
            default:
                callback.onContinue(postcard);
            //在每一個元件中新增一個navi的攔截器  邏輯在

        }
    }

    @Override
    public void init(Context context) {
        this.context = context;
    }
}
  • 1.在跳轉homeActivity時,跳轉到home元件的homeInterceptor攔截器
  • 2.在homeInterceptor中通過component獲取login註冊的lohginservice來獲取登入狀態,實現下一步跳轉

可以看到 app 通過ARouter跳home home通過component的註冊分發,判斷登入邏輯 進行下一步跳轉;這樣就實現了不依賴其他元件的邏輯互動

5.元件化fragment解耦

在android中我們使用最多的就是fragment,一般情況下 我們會例項化fragment再進行下一步邏輯;為了解耦我們在component中註冊fragment介面,在相應元件中註冊fragmentservice,在其他元件中實現分發:

//component-LoginFragmentService
public class LoginFragmentService implements IFragmentService {


    @Override
    public Fragment getFragment(String tag) {
        return new LginHomeFragment();
    }

    @Override
    public void newFragment(Activity activity, int resId, FragmentManager fragmentManager, Bundle bundle, String tag) {
        FragmentTransaction transaction = fragmentManager.beginTransaction();
        transaction.add(resId,new LginHomeFragment(),tag);
        transaction.commit();
    }
}

//component-ComponentServiceFactory
public class ComponentServiceFactory {

    private static volatile ComponentServiceFactory instance;
    private IFragmentService newsFragmentService;
    private IFragmentService homeFragmentService;
    private IFragmentService loginFragmentService;

    public static ComponentServiceFactory getInstance(Context context){
        if (instance == null){
            synchronized (ComponentServiceFactory.class){
                if (instance == null){
                    instance = new ComponentServiceFactory();
                }
            }
        }
        return instance;
    }

........
    //主冊fragmentservice入口
    public void setHomeFragmentService(IFragmentService iFragmentService){
        homeFragmentService = iFragmentService;
    }

    public void setLoginFragmentService(IFragmentService iFragmentService){
        loginFragmentService = iFragmentService;
    }

    public void setNewsFragmentService(IFragmentService iFragmentService){
        newsFragmentService = iFragmentService;
    }

    public IFragmentService getNewsFragmentService() {
        return newsFragmentService;
    }

    public IFragmentService getHomeFragmentService() {
        return homeFragmentService;
    }

    public IFragmentService getLoginFragmentService() {
        return loginFragmentService;
    }
}


在home元件中進行fragmentservice的註冊工作:

//home-HomeApp
public class HomeApp extends BaseApp {


    @Override
    public void initMoudleApp(Application application) {
        if (BuildConfig
            
           

相關推薦

Android元件 -- 完全實踐方案

首先貼上原始碼地址,歡迎frok,歡迎start 原始碼地址 目前,Android 元件化普遍使用於移動開發,但是元件化的初衷是為了解耦程式碼,並行開發效率;小型app似乎會care不到,完全解耦的元件化會在app越來越臃腫的時候帶來很大的提升; 1.元件化

Android元件框架設計與實踐

轉載自:Android元件化框架設計與實踐 在目前移動網際網路時代,每個 APP 就是流量入口,與過去 PC Web 瀏覽器時代不同的是,APP 的體驗與迭代速度影響著使用者的粘性,這同時也對從事移動開發人員提出更高要求,進而移動端框架也層出不窮。 服務端與移動端對比 上圖顯示的是

Android 元件間的

EventBus、Otto, Android 自身提供的BroadcastReceiver/Intent System 和利用Handler實現的類似廣播功能 用來簡化應用元件間的通訊。對比主要如下:  Otto 主要使用Bus類和兩個註解@Produce, @Subsc

Android元件方案實踐與思考

Demo地址:https://github.com/751496032/ComponentDemo 效果圖: 背景 Android從誕生到現在,不知不覺的走過十多個年頭了,也產生了很多App,隨著專案的推進不斷的迭代,而App也從最初的單一功能演變成多工功能,各種業務的錯綜

Android元件框架專案詳

簡介 什麼是元件化? 專案發展到一定階段時,隨著需求的增加以及頻繁地變更,專案會越來越大,程式碼變得越來越臃腫,耦合會越來越多,開發效率也會降低,這個時候我們就需要對舊專案進行重構即模組的拆分,官方的說法就是元件化。 元件化帶來的好處 那麼,採用元件化能帶來什麼好處呢?主要有以下兩點: 1、

迴歸初心:極簡 Android 元件方案 — AppJoint

Android 元件化的概念大概從兩年前開始有人討論,到目前為止,技術已經慢慢沉澱下來,越來越多團隊開源了自己元件化框架。本人所在團隊從去年開始調研元件化框架,在瞭解社群眾多元件化方案之後,決定自研元件化方案。為什麼明明已經有很多輪子可以用了,卻還是決定要自己造個新輪子呢?

android元件方案整理

為什麼要元件化? 在這之前我們先看一個圖,摘自我的腦圖: 所以,一直是需求再推動著我們前進,還有萬惡的產品!!! 目前的主流方案:主工程多子工程開發模型 所有業務元件不再是mouble而是作為一個子工程,基礎元件可以使moudle,也可以是子工程,該子

Android元件方案元件訊息匯流排modular-event實戰

背景 元件化作為Android客戶端技術的一個重要分支,近年來一直是業界積極探索和實踐的方向。美團內部各個Android開發團隊也在嘗試和實踐不同的元件化方案,並且在元件化通訊框架上也有很多高質量的產出。最近,我們團隊對美團零售收銀和美團輕收銀兩款Android App進行了元件化改造。本文主要介紹我們的元

得到App Android元件方案解析

為什麼要寫這篇文章 元件化已經深得客戶端開發大神們的認可,元件化確實進一步優化了客戶端團隊的開發效率,更適合大團隊分組推進,理解元件化的思想,深入研究元件化的實現方案是很必要的。 在接觸眾多元件化的方案後,自己也萌生了想搭建一套集眾家之所長的元件化方案。

Android元件開發實踐

前兩年安卓外掛化開發在國內進行的如火如荼,出現了不少外掛化的框架,360,攜程等都開源了比較好的外掛化框架,外掛化開發確實是可以給開發者帶來很大的方便。不過外掛化需要解決的問題太多,動態載入類,資源等等,首先就需要對安卓的打包機制,執行機制等等了解的很清楚。對個

Android元件方案—阿里路由ARouter的使用

1、為什麼要專案元件化 隨著APP版本不斷的迭代,新功能的不斷增加,業務也會變的越來越複雜,APP業務模組的數量有可能還會繼續增加,而且每個模組的程式碼也變的越來越多,這樣發展下去單一工程下的APP架構勢必會影響開發效率,增加專案的維護成本,每個工程師都要熟悉如此之多的程式碼,將很

Android元件方案

1、為什麼要專案元件化 隨著APP版本不斷的迭代,新功能的不斷增加,業務也會變的越來越複雜,APP業務模組的數量有可能還會繼續增加,而且每個模組的程式碼也變的越來越多,這樣發展下去單一工程下的APP架構勢必會影響開發效率,增加專案

Android元件之終極方案

Fragment或View如何支援元件化 距離 Android元件化方案 釋出已經半年有餘,雖說這個方案已經能夠解決一些專案的需求,但是依然不夠完美。很多開發者也在部落格和GitHub中留言甚至發郵件問我,Fragment怎麼辦?

模組式開發在螞蟻金服 mPaaS 深度實踐探討

前言 今天很高興有機會給大家分享支付寶的開發經驗,具體的內容將分成三個部分展開: 支付寶架構設計與發展; 支付寶的敏捷釋出與穩定性保障; 支付寶架構的優勢與賦能。 作為一個開發者,有一個學習的氛圍跟一個交流圈子特別重要這是一個我的QQ群架構華山論劍:8364424

【架構】android元件方案,讓團隊開發更有效率

剛接到Leader元件化任務的時候,內心是有疑惑的。目前專案中,各種業務交雜在一起,互相跳轉、互相請求資料。分模組的過程必然是痛苦的,需要增加模組之間通的信協議。對於一個5,6人的團隊來說,全都放在一個大模組中似乎也沒啥不好,可以隨心所欲地呼叫,節約思考框架合理性的時間。

Android元件專案詳細實施方案

1、Android元件化專案 在Android專案元件化之前,我們的專案都是像下圖那樣,一個單一工程下,根據不同的業務分幾個資料夾,把需要的第三方庫依賴下就開始開發了,這樣的程式碼耦合嚴重,牽一髮而動全身,刪除某處程式碼就會到處報錯,如果不解決掉報錯的地方,就沒法編譯打包,而且這樣的程式碼只適合於個人開發,

Android 元件方案,從入門到精通。apply plugin: ‘com.android.application’

目錄 8、結束語 1、為什麼要專案元件化 隨著APP版本不斷的迭代,新功能的不斷增加,業務也會變的越來越複雜,APP業務模組的數量有可能還會繼續增加,而且每個模組的程式碼也變

Android 元件最佳實踐 ARetrofit 原理

本文首發於 vivo網際網路技術 微信公眾號 https://mp.weixin.qq.com/s/TXFt7ymgQXLJ

Android元件元件通訊

Demo地址:https://github.com/751496032/ComponentDemo 本文是續上一篇Android元件化方案實踐與思考文章一些思考,主要是針對元件間通訊,比如: 每個元件如何初始化各自的資料 Activity間如何跳轉、Fragment例項

Android元件框架搭建

本篇文章已授權微信公眾號 hongyangAndroid (鴻洋)獨家釋出 背景 當一個專案經過N手人開發,N個產品經理的蹂躪,N長時間的維護,此時一定存在大量程式碼冗餘、業務耦合、專案臃腫,資原始檔大把重複等等,不堪重負。當需要增加新功能或者修改之前某個功能的時候,我相信很多同仁都說只敢