objetivo de aprendizaje:
Competencia en el desarrollo de componentes, configuración de enrutamiento
Contenido de aprendizaje:
** Antes de utilizar el desarrollo en componentes, primero debe aclarar el marco general del proyecto, dividir los módulos y el negocio (enfoque), y un buen comienzo tendrá un buen resultado. ** Una vez que el módulo esté claramente dividido, comience a configurar el módulo.
Como se muestra en la figura, tenemos que completar las siguientes funciones:
1. Haga clic en el centro comercial para ingresar a ShoppingModule
2. Haga clic en Iniciar sesión para ingresar a LoginModule
3. Haga clic en el área roja de la factura para mostrar la lista de facturas (Fragmento en otros módulos)
(shareModule es un módulo público)
Creado de la siguiente manera de acuerdo con los requisitos comerciales:
Agregue en el archivo gradle.properties de la aplicación para controlar si el módulo se ejecuta de forma independiente.
#配置某个组件是否可以独立运行
isShoppingRunAlone = true
isLoginRunALone = true
Luego configure la aplicación build.gradle.
apply plugin: 'com.android.application'
apply plugin: 'kotlin-android'
apply plugin: 'kotlin-android-extensions'
android {
compileSdkVersion 30
buildToolsVersion "29.0.3"
defaultConfig {
applicationId "com.example.moduledemo"
minSdkVersion 16
targetSdkVersion 30
versionCode 1
versionName "1.0"
testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
}
buildTypes {
release {
minifyEnabled false
proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro'
}
}
}
dependencies {
implementation fileTree(dir: "libs", include: ["*.jar"])
implementation "org.jetbrains.kotlin:kotlin-stdlib:$kotlin_version"
implementation 'androidx.core:core-ktx:1.3.0'
implementation 'androidx.appcompat:appcompat:1.1.0'
implementation 'androidx.constraintlayout:constraintlayout:1.1.3'
testImplementation 'junit:junit:4.12'
androidTestImplementation 'androidx.test.ext:junit:1.1.1'
androidTestImplementation 'androidx.test.espresso:espresso-core:3.2.0'
//导入公共模块
implementation project(':ShareModule')
// 根据gradle中的配置来决定是否引用module
if (!isLoginRunALone.toBoolean()){
implementation project(':LoginModule')
}
if (!isShoppingRunAlone.toBoolean()){
implementation project(':ShoppingModule')
}
}
Continúe configurando el archivo build.gradle de otros módulos.
if (isShoppingRunAlone.toBoolean()){
apply plugin: 'com.android.application'
}else {
apply plugin: 'com.android.library'
}
apply plugin: 'kotlin-android'
apply plugin: 'kotlin-android-extensions'
android {
compileSdkVersion 30
buildToolsVersion "29.0.3"
defaultConfig {
minSdkVersion 16
targetSdkVersion 30
versionCode 1
versionName "1.0"
testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
consumerProguardFiles "consumer-rules.pro"
}
buildTypes {
release {
minifyEnabled false
proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro'
}
}
sourceSets{
main{
// 在独立运行或者作为Libarary调试时,使用不同的AndroidManifest.xml文件
if (isShoppingRunAlone.toBoolean()){
manifest.srcFile 'src/main/manifest/AndroidManifest.xml'
}else {
manifest.srcFile 'src/main/AndroidManifest.xml'
}
}
}
}
dependencies {
implementation fileTree(dir: "libs", include: ["*.jar"])
implementation "org.jetbrains.kotlin:kotlin-stdlib:$kotlin_version"
implementation 'androidx.core:core-ktx:1.3.0'
implementation 'androidx.appcompat:appcompat:1.1.0'
testImplementation 'junit:junit:4.12'
androidTestImplementation 'androidx.test.ext:junit:1.1.1'
androidTestImplementation 'androidx.test.espresso:espresso-core:3.2.0'
//导入公共模块
implementation project(':ShareModule')
}
Utilice diferentes archivos de manifiesto en diferentes modos de funcionamiento.
Necesita crear una nueva carpeta de manifiesto en el directorio principal del módulo correspondiente (de lo contrario, no encontrará el archivo de manifiesto si lo ejecuta solo).
El archivo de manifiesto que se ejecuta por separado se establece de la siguiente manera:
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.example.loginmodule">
<application
android:allowBackup="true"
android:icon="@mipmap/ic_launcher"
android:label="@string/app_name"
android:roundIcon="@mipmap/ic_launcher_round"
android:supportsRtl="true"
android:theme="@style/AppTheme">
<activity android:name=".LoginActivity">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
</application>
</manifest>
Incorpore la configuración principal del archivo de manifiesto en tiempo de ejecución del módulo de la siguiente manera:
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.example.shoppingmodule">
<application>
<activity android:name=".ShoppingActivity"/>
</application>
</manifest>
Una vez completada toda la configuración, puede modificar el valor de la variable en gradle.properties, compilar para verificar si la configuración es correcta y si se reemplaza el archivo de manifiesto. Corre para ver si es normal.
A continuación, comience a configurar el enrutamiento.
Muchas personas se preguntan por qué necesitan usar saltos de enrutamiento si pueden obtener directamente la actividad del submódulo después de hacer referencia al módulo. Esto se debe a que el desarrollo del componente es hacer que un solo módulo se compile de forma independiente.Si el módulo principal hace referencia al nombre de clase del submódulo, el módulo principal se compilará de forma anormal cuando el submódulo se ejecute solo.
Necesitamos saber que un proyecto no puede tener solo un submódulo ¿Cómo usar el enrutamiento cuando nuestros otros submódulos quieren saltar entre sí? Así que necesitamos configurar el enrutamiento en ShareModule En la configuración anterior, importamos ShareModule en cada Módulo.
primer paso
Creamos una plantilla de salto correspondiente al Módulo
import android.content.Context;
import android.os.Bundle;
import androidx.fragment.app.Fragment;
import androidx.fragment.app.FragmentManager;
public interface ILoginService {
void launch(Context ctx, String targetClass);
}
import android.content.Context;
import android.os.Bundle;
import androidx.fragment.app.Fragment;
import androidx.fragment.app.FragmentManager;
public interface IShoppingService {
void launch(Context ctx, String string);
Fragment newBillFragment(FragmentManager fragmentManager, int viewId, Bundle bundle);
}
Segundo paso
Realice operaciones de transferencia de valor y lógica de salto en el módulo correspondiente
package com.example.loginmodule;
import android.content.Context;
import android.content.Intent;
import com.example.sharemodule.ILoginService;
public class LoginService implements ILoginService {
@Override
public void launch(Context ctx, String targetClass) {
Intent intent = new Intent(ctx, LoginActivity.class);
ctx.startActivity(intent);
}
}
package com.example.shoppingmodule;
import android.content.Context;
import android.content.Intent;
import android.os.Bundle;
import androidx.fragment.app.Fragment;
import androidx.fragment.app.FragmentManager;
import com.example.sharemodule.IShoppingService;
public class ShoppingService implements IShoppingService {
@Override
public void launch(Context ctx, String string) {
Intent intent = new Intent(ctx, ShoppingActivity.class);
ctx.startActivity(intent);
}
@Override
public Fragment newBillFragment(FragmentManager fragmentManager, int viewId, Bundle bundle) {
BillFragment fragment = new BillFragment();
fragment.setArguments(bundle);
fragmentManager.beginTransaction().replace(viewId, fragment).commit();
return fragment;
}
}
tercer paso
A continuación, creamos un ServiceFactory para proporcionarnos instancias de salto y manejar las excepciones que pueden ocurrir cuando se ejecuta solo.
package com.example.sharemodule;
public class ServiceFactory {
private static final ServiceFactory instance = new ServiceFactory();
private ILoginService mLoginService;
private IShoppingService mShoppingService;
private ServiceFactory(){}
public static ServiceFactory getInstance() {
return instance;
}
public ILoginService getLoginService() {
if (mLoginService == null){
mLoginService = new EmptyLoginService();
}
return mLoginService;
}
public void setLoginService(ILoginService mLoginService) {
this.mLoginService = mLoginService;
}
public IShoppingService getSignService() {
if (mShoppingService == null){
mShoppingService = new EmptyShoppingService();
}
return mShoppingService;
}
public void setSignService(IShoppingService mSignService) {
this.mShoppingService = mSignService;
}
}
package com.example.mylibrarySharedLibrary;
import android.content.Context;
import android.os.Bundle;
import androidx.fragment.app.Fragment;
import androidx.fragment.app.FragmentManager;
public class EmptyLoginService implements ILoginService {
@Override
public void launch(Context ctx, String targetClass) {
}
@Override
public Fragment newUserInfoFragment(FragmentManager fragmentManager, int viewId, Bundle bundle) {
return null;
}
}
package com.example.mylibrarySharedLibrary;
import android.content.Context;
public class EmptySignService implements ISignService {
@Override
public void launch(Context ctx, String userId) {
}
}
De esta manera, no ocurrirá ninguna excepción incluso cuando ejecutemos el Moudle principal solo.
El código que saltamos arriba está terminado. El siguiente paso es agregarlo a serviceFactory
mLoginService privado ILoginService;
IShoppingService privado mSignService;
Asignación
package com.example.sharemodule;
import android.app.Application;
public interface IComponentApplication {
void initialize(Application application);
}
Proporcionar una interfaz de inicialización unificada
package com.example.moduledemo;
import android.app.Application;
import android.util.Log;
import com.example.sharemodule.AppConfig;
import com.example.sharemodule.IComponentApplication;
public class MainApplication extends Application implements IComponentApplication {
private static Application application;
public static Application getApplication(){
return application;
}
@Override
public void onCreate() {
super.onCreate();
initialize(this);
}
@Override
public void initialize(Application application) {
for (String cpnt : AppConfig.Components){
try{
Class<?> clz = Class.forName(cpnt);
Object obj = clz.newInstance();
if (obj instanceof IComponentApplication){
((IComponentApplication) obj).initialize(this);
}
}catch (Exception e){
Log.e("TAG", e.getMessage());
}
}
}
}
package com.example.loginmodule;
import android.app.Application;
import com.example.sharemodule.IComponentApplication;
import com.example.sharemodule.ServiceFactory;
public class LoginApplication extends Application implements IComponentApplication {
private static Application application;
public static Application getApplication(){
return application;
}
@Override
public void onCreate() {
super.onCreate();
}
@Override
public void initialize(Application app) {
application = app;
ServiceFactory.getInstance().setLoginService(new LoginService());
}
}
package com.example.shoppingmodule;
import android.app.Application;
import com.example.sharemodule.IComponentApplication;
import com.example.sharemodule.ServiceFactory;
public class ShoppingApplication extends Application implements IComponentApplication {
private static Application application;
public static Application getApplication() {
return application;
}
@Override
public void onCreate() {
super.onCreate();
}
@Override
public void initialize(Application app) {
application = app;
ServiceFactory.getInstance().setSignService(new SignService());
}
}
package com.example.sharemodule;
public class AppConfig {
public static final String[] Components = {
"com.example.shoppingmodule.ShoppingApplication",
"com.example.loginmodule.LoginApplication"
};
}
Se inicializa al ingresar a la aplicación, y la instancia de la aplicación del submódulo se obtiene mediante reflexión para la inicialización.
Resultado final:
Este artículo está incluido en el proyecto de código abierto: https://github.com/Android-Alvin/Android-LearningNotes , que contiene el proyecto de código abierto más completo de componentes de Android (Meituan App, Get App, Alipay App, WeChat App, Aplicación Mogujie, Aplicación Youzan ...) etc. Los recursos se actualizan continuamente ...