Guia para iniciantes para evitar poços: explicação detalhada do desenvolvimento de componentes Android

alvo de aprendizagem:

Proficiência no desenvolvimento de componentes, configuração de roteamento


Conteúdo de aprendizagem:

** Antes de usar o desenvolvimento com componentes, você deve primeiro esclarecer a estrutura geral do projeto, dividir os módulos e o negócio (foco) e um bom começo terá um bom resultado. ** Depois que o módulo estiver claramente dividido, comece a configurar o módulo.

Conforme mostrado na figura, temos que completar as seguintes funções:

1. Clique no shopping para entrar no ShoppingModule

2. Clique em Login para entrar no LoginModule

3. Clique na área vermelha da conta para exibir a lista de contas (Fragmento em outros Módulos)

(shareModule é um módulo público)

Criado da seguinte forma de acordo com os requisitos de negócios:

Adicione no arquivo gradle.properties do aplicativo para controlar se o módulo é executado de forma independente.

#配置某个组件是否可以独立运行
isShoppingRunAlone = true
isLoginRunALone = true

Em seguida, configure o App 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')
    }
 
}

Continue a configurar o arquivo build.gradle de outros 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')
 
}

Use diferentes arquivos de manifesto em diferentes modos de operação.

Você precisa criar uma nova pasta de manifesto no diretório principal do módulo correspondente (caso contrário, você não encontrará o arquivo de manifesto se executá-lo sozinho).

O arquivo de manifesto executado separadamente é definido da seguinte maneira:

<?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 as configurações principais do arquivo de manifesto de tempo de execução do Módulo da seguinte maneira:

<manifest xmlns:android="http://schemas.android.com/apk/res/android"
    package="com.example.shoppingmodule">
 
    <application>
        <activity android:name=".ShoppingActivity"/>
    </application>
</manifest>

Depois que toda a configuração for concluída, você pode modificar o valor da variável em gradle.properties, compilar para verificar se a configuração está correta e se o arquivo de manifesto foi substituído. Corra para ver se está normal.

Em seguida, comece a configurar o roteamento.

Muitas pessoas estão se perguntando por que precisam usar os saltos de roteamento se podem obter diretamente a atividade do submódulo depois de fazer referência ao Módulo. É porque o desenvolvimento do componente é para fazer um único módulo compilar independentemente.Se o módulo principal fizer referência ao nome da classe do submódulo, o módulo principal irá compilar de forma anormal quando o submódulo for executado sozinho.

Precisamos saber que um projeto não pode ter apenas um submódulo.Como usar o roteamento quando nossos outros submódulos querem saltar um para o outro? Portanto, precisamos configurar o roteamento no ShareModule.Na configuração anterior, importamos ShareModule em cada Módulo.

Primeiro passo

Criamos um modelo de salto correspondente ao 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 passo

Realize a lógica de salto e as operações de transferência de valor no moudle correspondente

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;
    }
}

terceiro passo

Em seguida, criamos uma ServiceFactory para nos fornecer instâncias de salto e lidar com exceções que podem ocorrer quando executado sozinho

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) {
 
    }
}

Dessa forma, nenhuma exceção ocorrerá, mesmo quando executarmos o Moudle principal sozinhos.

O código que pulamos acima está concluído. A próxima etapa é adicionar à serviceFactory

private ILoginService mLoginService;
private IShoppingService mSignService;

Tarefa

package com.example.sharemodule;
 
import android.app.Application;
 
public interface IComponentApplication {
    void initialize(Application application);
}

Fornece interface de inicialização 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"
    };
}

Ele é inicializado ao entrar no App, e a instância do Application do submódulo é obtida através de reflexão para inicialização.

Resultado final:

Este artigo  está incluído no projeto de código aberto: https://github.com/Android-Alvin/Android-LearningNotes , que contém o projeto de código aberto mais totalmente aberto de componentes Android (Meituan App, Get App, Alipay App, WeChat App, Mogujie App, Youzan APP ...) etc. Os recursos estão sendo atualizados continuamente ...

Acho que você gosta

Origin blog.csdn.net/weixin_43901866/article/details/112492393
Recomendado
Clasificación