欧美bbbwbbbw肥妇,免费乱码人妻系列日韩,一级黄片

Android組件化原理詳細(xì)介紹

 更新時(shí)間:2022年07月28日 15:11:31   作者:西郵王嘉爾  
這篇文章主要介紹了Android組件化原理詳細(xì)介紹,組件化架構(gòu)的目的是讓各個(gè)業(yè)務(wù)變得相對(duì)獨(dú)立,各個(gè)組件在組件模式下可以獨(dú)立開(kāi)發(fā)調(diào)試

什么是組件化?

一個(gè)大型APP版本一定會(huì)不斷的迭代,APP里的功能也會(huì)隨之增加,項(xiàng)目的業(yè)務(wù)也會(huì)變的越來(lái)越復(fù)雜,這樣導(dǎo)致項(xiàng)目代碼也變的越來(lái)越多,開(kāi)發(fā)效率也會(huì)隨之下降。并且單一工程下代碼耦合嚴(yán)重,每修改一處代碼后都要重新編譯,非常耗時(shí),單獨(dú)修改的一個(gè)模塊無(wú)法單獨(dú)測(cè)試。

組件化架構(gòu)的目的是讓各個(gè)業(yè)務(wù)變得相對(duì)獨(dú)立,各個(gè)組件在組件模式下可以獨(dú)立開(kāi)發(fā)調(diào)試,集成模式下又可以集成到“app殼工程”中,從而得到一個(gè)具有完整功能的APP。

組件化每一個(gè)組件都可以是一個(gè)APP可以單獨(dú)修改調(diào)試,而不影響總項(xiàng)目。

組件化基礎(chǔ)架構(gòu)圖

為什么使用組件化?

編譯速度: 可以但需測(cè)試單一模塊,極大提高了開(kāi)發(fā)速度
超級(jí)解耦: 極度降低了模塊間的耦合,便于后期的維護(hù)和更新
功能重用: 某一塊的功能在另外的組件化項(xiàng)目中使用只需要單獨(dú)依賴這一模塊即可
便于團(tuán)隊(duì)開(kāi)發(fā): 組件化架構(gòu)是團(tuán)隊(duì)開(kāi)發(fā)必然會(huì)選擇的一種開(kāi)發(fā)方式,它能有效的使團(tuán)隊(duì)更好的協(xié)作

一步步搭建組件化

這里以演示為例,只設(shè)置登錄這一個(gè)功能組件

組件化開(kāi)發(fā)要注意的幾點(diǎn)問(wèn)題 :

  • 要注意包名和資源文件命名沖突問(wèn)題
  • Gradle中的版本號(hào)的統(tǒng)一管理
  • 組件在AppIicationLibrary之間如何做到隨意切換
  • AndroidManifest. xml文件的區(qū)分
  • Library不能在Gradle文件中有applicationId

這里以演示為例,只設(shè)置登錄和個(gè)人中心這兩個(gè)功能組件

1.新建模塊

在這里插入圖片描述

并且在module里新建一個(gè)activity

在這里插入圖片描述

到這里我們看到login和我們的app都在有一個(gè)綠點(diǎn)證明創(chuàng)建成功

在這里插入圖片描述

個(gè)人中心member模塊創(chuàng)建同理,并且每個(gè)模塊目前都可以獨(dú)立運(yùn)行。

在這里插入圖片描述

2.統(tǒng)一Gradle版本號(hào)

每一個(gè)模塊都是一個(gè)application,所以每個(gè)模塊都會(huì)有一個(gè)build.gradle,各個(gè)模塊里面的配置不同,我們需要重新統(tǒng)一Gradle
在主模塊創(chuàng)建config.gradle

在這里插入圖片描述

config.gradle里去添加一些版本號(hào)

ext{
    android = [
            compileSdkVersion :30,
            buildToolsVersion: "30.0.2",
            applicationId :"activitytest.com.example.moduletest",
            minSdkVersion: 29,
            targetSdkVersion :30,
            versionCode :1,
            versionName :"1.0",
    ]
    androidxDeps = [
            "appcompat": 'androidx.appcompat:appcompat:1.1.0',
            "material": 'com.google.android.material:material:1.1.0',
            "constaraintlayout": 'androidx.constraintlayout:constraintlayout:1.1.3',
    ]
    commonDeps = [
            "arouter_api"          : 'com.alibaba:arouter-api:1.5.1',
            "glide"                : 'com.github.bumptech.glide:glide:4.11.0'

    ]
    annotationDeps = [
            "arouter_compiler" : 'com.alibaba:arouter-compiler:1.5.1'
    ]
    retrofitDeps = [
            "retrofit"  : 'com.squareup.retrofit2:retrofit:2.9.0',
            "converter" : 'com.squareup.retrofit2:converter-gson:2.9.0',
            "rxjava"    : 'io.reactivex.rxjava2:rxjava:2.2.20',
            "rxandroid" : 'io.reactivex.rxjava2:rxandroid:2.1.1',
            "adapter"   : 'com.squareup.retrofit2:adapter-rxjava2:2.9.0'
    ]
    androidxLibs = androidxDeps.values()
    commonLibs = commonDeps.values()
    annotationLibs = annotationDeps.values()
    retrofitLibs = retrofitDeps.values()
}

在主模塊的build.gradle里添加

apply from: "config.gradle"

在這里插入圖片描述

在各模塊中去引用這些版本號(hào)
引用格式如下,兩種寫(xiě)法均可

compileSdkVersion rootProject.ext.android["compileSdkVersion"]
buildToolsVersion rootProject.ext.android.buildToolsVersion

引用前:

在這里插入圖片描述

引用后:

在這里插入圖片描述

并且使用同樣的方法,我們還可以統(tǒng)一我們的依賴庫(kù)在config.gradle里去添加我們要依賴的庫(kù),并在各個(gè)模塊中去添加依賴

 implementation  rootProject.ext.dependencies.publicImplementation

也可以采用第二種寫(xiě)法

dependencies = [

            "appcompat"             : 'androidx.appcompat:appcompat:1.2.0',

            "material"               : 'com.google.android.material:material:1.2.1',
            "constraintLayout"       : 'androidx.constraintlayout:constraintlayout:2.0.4',//約束性布局

            //test
            "junit"                  : "junit:junit:4.13.1",
            "testExtJunit"           : 'androidx.test.ext:junit:1.1.2',//測(cè)試依賴,新建項(xiàng)目時(shí)會(huì)默認(rèn)添加,一般不建議添加
            "espressoCore"           : 'androidx.test.espresso:espresso-core:3.3.0',//測(cè)試依賴,新建項(xiàng)目時(shí)會(huì)默認(rèn)添加,一般不建議添加

    ]

添加依賴:

dependencies {

    implementation rootProject.ext.dependencies.appcompat
    implementation  rootProject.ext.dependencies["constraintLayout"]
    testImplementation rootProject.ext.dependencies["junit"]
    androidTestImplementation rootProject.ext.dependencies["testExtJunit"]
    androidTestImplementation rootProject.ext.dependencies["espressoCore"]

}

3.創(chuàng)建基礎(chǔ)庫(kù)

和新建module一樣,這里需要新建一個(gè)library我們把它命名為Baselibs

在這里插入圖片描述

同樣需要統(tǒng)一版本號(hào),由于這是一個(gè)library模塊,所以它不需要applicationId

在這里插入圖片描述

我們一樣可以把它寫(xiě)進(jìn)config.gradle

other:[path:':Baselibs']

在每個(gè)模塊去調(diào)用

implementation  project(rootProject.ext.dependencies.other)

同理,當(dāng)本地庫(kù)為單獨(dú)所用,我們可以直接調(diào)用,而不需要將其寫(xiě)入config.gradle,兩種方法選擇合適使用即可。

implementation project(':Baselibs')

但有時(shí)因?yàn)?code>gradle版本問(wèn)題,我們可能無(wú)法依賴到這些公共庫(kù),因?yàn)槲覀冊(cè)?code>config.gradle里是以數(shù)組形式定義的,這時(shí)我們可以同for-each循環(huán)的方法將其依次導(dǎo)入
config.gradle

dependencies = [
          ......
        other:[':Baselibs']
    ]

其他模塊的build.gradle

dependencies {
......
    rootProject.ext.dependencies.other.each{
        implementation project(it)
    }

4.組件模式和集成模式轉(zhuǎn)換

在主模塊gradle.properties里添加布爾類(lèi)型選項(xiàng)。

在這里插入圖片描述

在各個(gè)模塊的build.gradle里添加更改語(yǔ)句

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

每個(gè)模塊的applicationId也需要處理

if(is_Module.toBoolean()){
            applicationId "activitytest.com.example.login"
        }

在這里插入圖片描述

當(dāng)我們將is_module改為false時(shí),再次運(yùn)行編譯器我們的模塊都不能單獨(dú)運(yùn)行了

在這里插入圖片描述

在app模塊中添加判斷依賴就可以在集成模式下將各模塊添加到app主模塊中

// 每加入一個(gè)新的模塊,就需要在下面對(duì)應(yīng)的添加一行
    if (is_Module.toBoolean())]) {
        implementation project(path:':login')
        implementation project(path:':member')
    }

5.AndroidManifest的切換

為了單獨(dú)開(kāi)發(fā)加載不同的AndroidManifest這里需要重新區(qū)分下。
在組件模塊里的main文件里新建manifest文件夾

在這里插入圖片描述

并且重寫(xiě)一個(gè)AndroidManifest.xml文件,集成模式下,業(yè)務(wù)組件的表單是絕對(duì)不能擁有自己的 Application 和 launch 的 Activity的,也不能聲明APP名稱、圖標(biāo)等屬性,總之a(chǎn)pp殼工程有的屬性,業(yè)務(wù)組件都不能有,在這個(gè)表單中只聲明了應(yīng)用的主題,而且這個(gè)主題還是跟app殼工程中的主題是一致的

<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
    package="com.example.login">

    <application
        android:theme="@style/Theme.MoudleTest">
        <activity android:name=".LoginActivity">
       
        </activity>
    </application>

</manifest>

并且我們還要使其在不同的模式下加載不同的AndroidManifest只需在各模塊的build.gradle里添加更改語(yǔ)句

sourceSets {
        main {
            if (is_Module.toBoolean()) {
                manifest.srcFile 'src/main/AndroidManifest.xml'
            } else {
                manifest.srcFile 'src/main/mainfest/AndroidManifest.xml'
            }
        }
    }

6.*業(yè)務(wù)Application切換

每個(gè)模塊在運(yùn)行時(shí)都會(huì)有自己的application,而在組件化開(kāi)發(fā)過(guò)程中,我們的主模塊只能有一個(gè)application,但在單獨(dú)運(yùn)行時(shí)又需要自己的application這里就需要配置一下。
在業(yè)務(wù)模塊添加新文件夾命名module

在這里插入圖片描述

在里面建一個(gè)application文件

在這里插入圖片描述

并且我們?cè)?code>build.gradle文件里配置module文件夾使其在單獨(dú)運(yùn)行時(shí)能夠運(yùn)行單獨(dú)的application
在配置manifest的語(yǔ)句中添加java.srcDir 'src/main/module'

sourceSets {
        main {
            if (is_Module.toBoolean()) {
                manifest.srcFile 'src/main/AndroidManifest.xml'
                java.srcDir 'src/main/module'
            } else {
                manifest.srcFile 'src/main/manifest/AndroidManifest.xml'
            }
        }
    }

同時(shí)我們?cè)?code>basic基礎(chǔ)層內(nèi)新建application,用于加載一些數(shù)據(jù)的初始化

public class BaseApplication extends Application {
    @Override
    public void onCreate() {
        super.onCreate();
        Log.e("fff","baseapplication");
    }
}

在業(yè)務(wù)模塊內(nèi)module里重寫(xiě)該模塊的application

public class LoginApplication extends BaseApplication {
    @Override
    public void onCreate() {
        super.onCreate();
    }
}

至此,組件化框架搭建結(jié)束

組件之間的跳轉(zhuǎn)

這里采用阿里巴巴的開(kāi)源庫(kù)ARouter來(lái)實(shí)現(xiàn)跳轉(zhuǎn)功能,我會(huì)在以后的文章單獨(dú)拿出一篇來(lái)一步步去解讀Arouter源碼,讓我們自己去搭建一個(gè)自己的路由

一個(gè)用于幫助 Android App 進(jìn)行組件化改造的框架 —— 支持模塊間的路由、通信、解耦

由 github 上 ARouter 的介紹可以知道,它可以實(shí)現(xiàn)組件間的路由功能。路由是指從一個(gè)接口上收到數(shù)據(jù)包,根據(jù)數(shù)據(jù)路由包的目的地址進(jìn)行定向并轉(zhuǎn)發(fā)到另一個(gè)接口的過(guò)程。這里可以體現(xiàn)出路由跳轉(zhuǎn)的特點(diǎn),非常適合組件化解耦。

要使用 ARouter 進(jìn)行界面跳轉(zhuǎn),需要我們的組件對(duì) Arouter 添加依賴,因?yàn)樗械慕M件都依賴了 Baselibs模塊,所以我們?cè)?Baselibs 模塊中添加 ARouter 的依賴即可。其它組件共同依賴的庫(kù)也最好都放到 Baselibs中統(tǒng)一依賴。

這里需要注意的是,arouter-compiler 的依賴需要所有使用到 ARouter 的模塊和組件中都單獨(dú)添加,不然無(wú)法在 apt 中生成索引文件,也就無(wú)法跳轉(zhuǎn)成功。并且在每一個(gè)使用到 ARouter 的模塊和組件的 build.gradle 文件中,其 android{} 中的 javaCompileOptions 中也需要添加特定配置。

1.添加依賴

Baselibs里的build.gradle添加依賴

dependencies {
    api 'com.alibaba:arouter-api:1.3.1'
    // arouter-compiler 的注解依賴需要所有使用 ARouter 的 module 都添加依賴
    annotationProcessor 'com.alibaba:arouter-compiler:1.1.4'
}
// 所有使用到 ARouter 的組件和模塊的 build.gradle
android {
    defaultConfig {
        ...
        javaCompileOptions {
            annotationProcessorOptions {
                arguments = [ moduleName : project.getName() ]
            }
        }
    }
}
dependencies {
    ...
    implementation project (':base')
    annotationProcessor 'com.alibaba:arouter-compiler:1.1.4'
}

主模塊需要對(duì)跳轉(zhuǎn)模塊進(jìn)行依賴:

// 主項(xiàng)目的 build.gradle 需要添加對(duì) login 組件和 share 組件的依賴
dependencies {
    // ... 其他
    implementation project(':login')
    implementation project(':share')
}

2.初始化ARouter

添加了對(duì) ARouter 的依賴后,還需要在項(xiàng)目的 Application 中將 ARouter 初始化,我們這里將 ARouter 的初始化工作放到主模塊Application 的 onCreate()方法中,在應(yīng)用啟動(dòng)的同時(shí)將 ARouter 初始化。

public class MainApplication extends Application {
    @Override
    public void onCreate() {
        super.onCreate();
        // 初始化 ARouter
        if (isDebug()) {           
            // 這兩行必須寫(xiě)在init之前,否則這些配置在init過(guò)程中將無(wú)效
            // 打印日志
            ARouter.openLog();     
            // 開(kāi)啟調(diào)試模式(如果在InstantRun模式下運(yùn)行,必須開(kāi)啟調(diào)試模式!線上版本需要關(guān)閉,否則有安全風(fēng)險(xiǎn))
            ARouter.openDebug();   
        }

        // 初始化 ARouter
        ARouter.init(this);

    }
    private boolean isDebug() {
        return BuildConfig.DEBUG;
    }
}

3.添加跳轉(zhuǎn)

這里我們?cè)谑醉?yè)添加登錄分享兩個(gè)跳轉(zhuǎn)頁(yè)面。

login.setOnClickListener(new View.OnClickListener() {
    @Override
    public void onClick(View v) {
        ARouter.getInstance().build("/login/login").navigation();
    }
});
share.setOnClickListener(new View.OnClickListener() {
    @Override
    public void onClick(View v) {
        ARouter.getInstance().build("/share/share").navigation();
    }
});

然后,需要在登錄和分享組件中分別添加 LoginActivityShareActivity ,然后分別為兩個(gè) Activity 添加注解 Route,其中path 是跳轉(zhuǎn)的路徑,這里的路徑需要注意的是至少需要有兩級(jí),/xx/xx

@Route(path = "/login/login")
public class Login extends AppCompatActivity {
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_login);

    }
}
@Route(path = "/share/share")
public class Share extends AppCompatActivity {

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

這樣就可以實(shí)現(xiàn)跳轉(zhuǎn)了。

組件之間的數(shù)據(jù)傳遞

由于主項(xiàng)目與組件,組件與組件之間都是不可以直接使用類(lèi)的相互引用來(lái)進(jìn)行數(shù)據(jù)傳遞的,那么在開(kāi)發(fā)過(guò)程中如果有組件間的數(shù)據(jù)傳遞時(shí)應(yīng)該如何解決呢,這里我們可以采用 [接口 + 實(shí)現(xiàn)] 的方式來(lái)解決。

Baselibs基礎(chǔ)庫(kù)里定義組件可以對(duì)外提供訪問(wèn)自身數(shù)據(jù)的抽象方法的 Service。并且提供了一個(gè) ServiceFactory,每個(gè)組件中都要提供一個(gè)類(lèi)實(shí)現(xiàn)自己對(duì)應(yīng)的 Service 中的抽象方法。在組件加載后,需要?jiǎng)?chuàng)建一個(gè)實(shí)現(xiàn)類(lèi)的對(duì)象,然后將實(shí)現(xiàn)了 Service 的類(lèi)的對(duì)象添加到ServiceFactory 中。這樣在不同組件交互時(shí)就可以通過(guò) ServiceFactory 獲取想要調(diào)用的組件的接口實(shí)現(xiàn),然后調(diào)用其中的特定方法就可以實(shí)現(xiàn)組件間的數(shù)據(jù)傳遞與方法調(diào)用。

當(dāng)然,ServiceFactory 中也會(huì)提供所有的 Service 的空實(shí)現(xiàn),在組件單獨(dú)調(diào)試或部分集成調(diào)試時(shí)避免出現(xiàn)由于實(shí)現(xiàn)類(lèi)對(duì)象為空引起的空指針異常。

下面我們就按照這個(gè)方法來(lái)解決組件間數(shù)據(jù)傳遞與方法的相互調(diào)用這個(gè)問(wèn)題,這里我們通過(guò)分享組件 中調(diào)用 登錄組件 中的方法來(lái)獲取登錄狀態(tài)是否登錄這個(gè)場(chǎng)景來(lái)演示。

1.定義接口

其中 service文件夾中定義接口,LoginService 接口中定義了 Login 組件向外提供的數(shù)據(jù)傳遞的接口方法,EmptyService 中是 service 中定義的接口的空實(shí)現(xiàn),ServiceFactory 接收組件中實(shí)現(xiàn)的接口對(duì)象的注冊(cè)以及向外提供特定組件的接口實(shí)現(xiàn)。

在這里插入圖片描述

LoginService

public interface LoginService {
    /**
     * 是否已經(jīng)登錄
     * @return
     */
    boolean isLogin();
    /**
     * 獲取登錄用戶的 Password
     * @return
     */
    String getPassword();
}

EmptyService

public class EmptyService implements LoginService {
    @Override
    public boolean isLogin() {
        return false;
    }

    @Override
    public String getPassword() {
        return null;
    }
}

ServiceFactory

public class ServiceFactory {
    private LoginService loginService;
    private ServiceFactory(){
 /**
     * 禁止外部創(chuàng)建 ServiceFactory 對(duì)象
     */
    private ServiceFactory() {
    }
    /**
     * 通過(guò)靜態(tài)內(nèi)部類(lèi)方式實(shí)現(xiàn) ServiceFactory 的單例
     */
    public static ServiceFactory getInstance() {
        return Inner.serviceFactory;
    }
    private static class Inner {
        private static ServiceFactory serviceFactory = new ServiceFactory();
    }
 /**
     * 接收 Login 組件實(shí)現(xiàn)的 Service 實(shí)例
     */
    public void setLoginService(LoginService loginService){
        this.loginService = loginService;
    }
       /**
     * 返回 Login 組件的 Service 實(shí)例
     */
    public LoginService getLoginService(){
        if(loginService == null){
            return new EmptyService();
        }else{
            return loginService;
        }
    }
}

2.實(shí)現(xiàn)接口

在login模塊

public class AccountService implements LoginService {

    private boolean login;
    private String password;

    public AccountService(boolean login, String password) {
        this.login = login;
        this.password = password;
    }

    @Override
    public boolean isLogin() {
        return login;
    }

    @Override
    public String getPassword() {
        return password;
    }
}

這里新建一個(gè)Util類(lèi)用來(lái)存儲(chǔ)登錄數(shù)據(jù)

public class LoginUtil {
    static boolean isLogin = false;
    static String password = null;
}

實(shí)現(xiàn)一下登錄操作

login = (Button)findViewById(R.id.login);
        login.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                LoginUtil.isLogin = true;
                LoginUtil.password = "admin";
                ServiceFactory.getInstance().setLoginService(new AccountService(LoginUtil.isLogin,LoginUtil.password));
            }
        });

在login模塊的application里定義ServiceFactory類(lèi)

public class LoginApplication extends Application {
    @Override
    public void onCreate() {
        super.onCreate();
        ServiceFactory.getInstance().setLoginService(new AccountService(LoginUtil.isLogin,LoginUtil.password));
    }
}

在分享模塊獲取登錄信息

share = (Button)findViewById(R.id.share);
        share.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                if(ServiceFactory.getInstance().getLoginService().isLogin()){
                    Toast.makeText(ShareActivity.this,"分享成功!",Toast.LENGTH_SHORT).show();
                }else{
                    Toast.makeText(ShareActivity.this,"分享失敗,請(qǐng)先登錄!",Toast.LENGTH_SHORT).show();
                }
            }
        });

一個(gè)項(xiàng)目時(shí)只能有一個(gè) Application 的,Login 作為組件時(shí),主模塊的 Application 類(lèi)會(huì)初始化,而 Login 組件中的 Applicaiton 不會(huì)初始化。確實(shí)是存在這個(gè)問(wèn)題的,我們這里先將 Service 的注冊(cè)放到其活動(dòng)里,稍后我們會(huì)解決 Login 作為組件時(shí) Appliaciton 不會(huì)初始化的問(wèn)題。

組件Application的動(dòng)態(tài)切換

在主模塊中有 Application 等情況下,組件在集中調(diào)試時(shí)其 Applicaiton 不會(huì)初始化的問(wèn)題。而我們組件的 Service 在 ServiceFactory 的注冊(cè)又必須放到組件初始化的地方。

為了解決這個(gè)問(wèn)題可以將組件的 Service 類(lèi)強(qiáng)引用到主 Module 的 Application 中進(jìn)行初始化,這就必須要求主模塊可以直接訪問(wèn)組件中的類(lèi)。而我們又不想在開(kāi)發(fā)過(guò)程中主模塊能訪問(wèn)組件中的類(lèi),這里可以通過(guò)反射來(lái)實(shí)現(xiàn)組件 Application 的初始化。

1.定義抽象類(lèi) BaseApplication 繼承 Application

Baselibs基礎(chǔ)庫(kù)模塊

public abstract class BaseApplication extends Application {
    /**
     * Application 初始化
     */
    public abstract void initModuleApp(Application application);

    /**
     * 所有 Application 初始化后的自定義操作
     */
    public abstract void initModuleData(Application application);              //其他需要調(diào)用的方法
}

2.所有的組件的 Application 都繼承 BaseApplication

這里我們以Login模塊為例

public class LoginApplication extends BaseApplication{
    @Override
    public void onCreate() {
        super.onCreate();
        initModuleApp(this);
        initModuleData(this);
    }
    @Override
    public void initModuleApp(Application application) {
        ServiceFactory.getInstance().setLoginService(new AccountService(LoginUtil.isLogin,LoginUtil.password));
    }
    @Override
    public void initModuleData(Application application) {

    }
}

3.定義 AppConfig 類(lèi)

Baselibs模塊定義一個(gè)靜態(tài)的 String 數(shù)組,我們將需要初始化的組件的 Application 的完整類(lèi)名放入到這個(gè)數(shù)組中。

public class AppConfig {
    private static final String LoginApp = "com.example.login.LoginApplication";
    public static String[] moduleApps = {
            LoginApp
    };
}

4.主模塊application實(shí)現(xiàn)兩個(gè)初始化方法

// 主 Module 的 Applicaiton
public class MainApplication extends BaseApp {
    @Override
    public void onCreate() {
        super.onCreate();
        
        // 初始化組件 Application
        initModuleApp(this);
        
        // 其他操作
        
        // 所有 Application 初始化后的操作
        initModuleData(this);
        
    }

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

到這里我們就通過(guò)反射,完成了組件 Application 的初始化操作,也實(shí)現(xiàn)了組件與化中的解耦需求。

主模塊使用其他組件的 Fragment

我們?cè)陂_(kāi)發(fā)過(guò)程中經(jīng)常使用 Fragment。一般情況下,我們都是直接通過(guò)訪問(wèn)具體 Fragment 類(lèi)的方式實(shí)現(xiàn) Fragment 的實(shí)例化,但是現(xiàn)在為了實(shí)現(xiàn)模塊與組件間的解耦,在移除組件時(shí)不會(huì)由于引用的 Fragment 不存在而編譯失敗,我們就不能模塊中直接訪問(wèn)組件的 Fragment 類(lèi)。
這里介紹兩種方法

1.ARouter

這里可以采用ARouter直接調(diào)用

fragment = (Fragment) ARouter.getInstance().build("/login/fragment").navigation();

2.反射

我們還是以Login模塊為例,假如在該模塊創(chuàng)建一個(gè)用戶界面,命名為UserFragment
首先,在 Login組件中創(chuàng)建 UserFragment,然后在 LoginService 接口中添加newUserFragment方法返回一個(gè)Fragment,在Login組件中的 AccountServiceBaselibsLoginService 的空實(shí)現(xiàn)類(lèi)中實(shí)現(xiàn)這個(gè)方法,然后在主模塊中通過(guò) ServiceFactory 獲取 LoginService 的實(shí)現(xiàn)類(lèi)對(duì)象,調(diào)用其 newUserFragment 即可獲取到 UserFragment 的實(shí)例。

// Baselibs 模塊的 LoginService 
public interface LoginService {
//其他代碼...
    Fragment newUserFragment(Activity activity, int containerId, FragmentManager manager, Bundle bundle, String tag);
}
// Login 組件中的 AccountService
public class AccountService implements LoginService {
    // 其他代碼 ...

    @Override
    public Fragment newUserFragment(Activity activity, int containerId, FragmentManager manager, Bundle bundle, String tag) {
        FragmentTransaction transaction = manager.beginTransaction();
        // 創(chuàng)建 UserFragment 實(shí)例,并添加到 Activity 中
        Fragment userFragment = new UserFragment();
        transaction.add(containerId, userFragment, tag);
        transaction.commit();
        return userFragment;
    }
}
// 主模塊的 FragmentActivity
public class FragmentActivity extends AppCompatActivity {

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_fragment);
        
        // 通過(guò)組件提供的 Service 實(shí)現(xiàn) Fragment 的實(shí)例化
        ServiceFactory.getInstance().getAccountService().newUserFragment(this, R.id.layout_fragment, getSupportFragmentManager(), null, "");
    }
}

到此這篇關(guān)于Android組件化原理詳細(xì)介紹的文章就介紹到這了,更多相關(guān)Android組件化 內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!

相關(guān)文章

  • Android串口通信之串口讀寫(xiě)實(shí)例

    Android串口通信之串口讀寫(xiě)實(shí)例

    這篇文章主要為大家詳細(xì)介紹了Android串口通信之串口讀寫(xiě)實(shí)例,具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下
    2018-04-04
  • android全局監(jiān)控click事件的四種方式(小結(jié))

    android全局監(jiān)控click事件的四種方式(小結(jié))

    本篇文章主要介紹了android全局監(jiān)控click事件的四種方式(小結(jié)),詳細(xì)介紹如何在全局上去監(jiān)聽(tīng) click 點(diǎn)擊事件,并做些通用處理或是攔截,有興趣的可以了解一下
    2017-08-08
  • Android Spinner 組件的應(yīng)用實(shí)例

    Android Spinner 組件的應(yīng)用實(shí)例

    這篇文章主要介紹了Android Spinner 組件的應(yīng)用實(shí)例的相關(guān)資料,希望通過(guò)本文大家能夠掌握這部分內(nèi)容,需要的朋友可以參考下
    2017-09-09
  • Android retrofit上傳文件實(shí)例(包含頭像)

    Android retrofit上傳文件實(shí)例(包含頭像)

    下面小編就為大家分享一篇Android retrofit上傳文件實(shí)例(包含頭像),具有很好的參考價(jià)值,希望對(duì)大家有所幫助。一起跟隨小編過(guò)來(lái)看看吧
    2018-01-01
  • Android沉浸式狀態(tài)欄設(shè)計(jì)的實(shí)例代碼

    Android沉浸式狀態(tài)欄設(shè)計(jì)的實(shí)例代碼

    本篇文章主要介紹了Android沉浸式狀態(tài)欄設(shè)計(jì)的實(shí)例代碼,整理了詳細(xì)的代碼,具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下
    2017-07-07
  • AOSP源碼下載示例代碼

    AOSP源碼下載示例代碼

    這篇文章主要介紹了AOSP源碼下載,由于清華源中給出很清晰的配置下載方法,這兒只做幾條總結(jié),對(duì)AOSP源碼感興趣的朋友一起看看吧
    2022-08-08
  • 詳解Android廣播Broadcast的啟動(dòng)流程

    詳解Android廣播Broadcast的啟動(dòng)流程

    這篇文章主要為大家介紹了Android廣播Broadcast啟動(dòng)流程詳解,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪
    2023-03-03
  • Android基于虹軟(ArcSoft)實(shí)現(xiàn)人臉識(shí)別

    Android基于虹軟(ArcSoft)實(shí)現(xiàn)人臉識(shí)別

    人工智能時(shí)代快速來(lái)臨,其中人臉識(shí)別是當(dāng)前比較熱門(mén)的技術(shù),在國(guó)內(nèi)也越來(lái)越多的運(yùn)用,例如刷臉打卡,刷臉APP,身份識(shí)別,人臉門(mén)禁等。本文將為大家介紹Android基于虹軟(ArcSoft)實(shí)現(xiàn)人臉識(shí)別的demo,快來(lái)跟隨小編一起學(xué)習(xí)吧
    2021-12-12
  • Android RecyclerView 實(shí)現(xiàn)快速滾動(dòng)的示例代碼

    Android RecyclerView 實(shí)現(xiàn)快速滾動(dòng)的示例代碼

    本篇文章主要介紹了Android RecyclerView 實(shí)現(xiàn)快速滾動(dòng)的示例代碼,具有一定的參考價(jià)值,有興趣的可以了解一下
    2017-09-09
  • Android中View.post和Handler.post的關(guān)系

    Android中View.post和Handler.post的關(guān)系

    這篇文章主要介紹了Android中View.post和Handler.post的關(guān)系,View.post和Handler.post是Android開(kāi)發(fā)中經(jīng)常使用到的兩個(gè)”post“方法,關(guān)于兩者存在的區(qū)別與聯(lián)系,文章詳細(xì)分析需要的小伙伴可以參考一下
    2022-06-06

最新評(píng)論