美文网首页组件化
组件化 -- Demo

组件化 -- Demo

作者: TomyZhang | 来源:发表于2020-02-18 20:47 被阅读0次

功能

  • 版本参数优化:common_config.gradle
  • 动态创建Fragment:ViewPager+Fragment
  • 动态初始化Application:IBaseAppInit
  • 组件间通信:EventBus
  • 组件间跳转:ARouter
  • 组件化存储:GreenDao
  • 组件化权限:PermissionSDK
  • 调试优化:isDebugModuleDebug
  • Gradle 4.1依赖特性:implementation、API

架构

组件化架构

代码

1.settings.gradle

include ':app', ':modulea', ':moduleb', ':modulec', ':base', ':permission', ':debugmodule'
rootProject.name='ModuleTest'

2.build.gradle(project)

// Top-level build file where you can add configuration options common to all sub-projects/modules.

buildscript {
    repositories {
        google()
        jcenter()
    }
    dependencies {
        classpath 'com.android.tools.build:gradle:3.2.1'
        //GreenDao 1
        classpath 'org.greenrobot:greendao-gradle-plugin:3.2.2'
        // NOTE: Do not place your application dependencies here; they belong
        // in the individual module build.gradle files
    }
}

allprojects {
    repositories {
        google()
        jcenter()
    }
}

task clean(type: Delete) {
    delete rootProject.buildDir
}

3.common_config.gradle(project)

project.ext {
    //设置App配置
    setAppDefaultConfig = {
        extension ->
            //引用Application插件库
            extension.apply plugin: 'com.android.application'
            //GreenDao 2
            extension.apply plugin: 'org.greenrobot.greendao'
            extension.description "app"
            setAndroidConfig extension.android
            setDependencies extension.dependencies
    }

    //设置Lib配置
    setLibDefaultConfig = {
        extension ->
            //引用lib插件库
            extension.apply plugin: 'com.android.library'
            //GreenDao 3
            extension.apply plugin: 'org.greenrobot.greendao'
            extension.description "lib"
            setAndroidConfig extension.android
            setDependencies extension.dependencies
    }

    //设置Android配置
    setAndroidConfig = {
        extension ->
            extension.compileSdkVersion 29
            extension.buildToolsVersion "29.0.0"
            extension.defaultConfig {
                minSdkVersion 15
                targetSdkVersion 29
                testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
                //ARouter 1
                javaCompileOptions {
                    annotationProcessorOptions {
                        arguments = [AROUTER_MODULE_NAME : extension.project.getName()]
                    }
                }
            }
    }

    //设置依赖
    setDependencies = {
        extension ->
            extension.implementation fileTree(dir: 'libs', include: ['*.jar'])
            extension.implementation 'androidx.appcompat:appcompat:1.1.0'
            extension.testImplementation 'junit:junit:4.12'
            extension.androidTestImplementation 'androidx.test.ext:junit:1.1.1'
            extension.androidTestImplementation 'androidx.test.espresso:espresso-core:3.2.0'
            //ARouter 2
            extension.annotationProcessor 'com.alibaba:arouter-compiler:1.2.2'
    }

    //调试优化 1
    //声明单独模块调试变量
    isDebugModuleDebug = false
}

4.应用层:App

//build.gradle
apply from: "${rootProject.rootDir}/common_config.gradle"
project.ext.setAppDefaultConfig project

android {
    defaultConfig {
        applicationId "com.tomorrow.moduletest"
        versionCode 1
        versionName "1.0"
    }
    buildTypes {
        release {
            minifyEnabled false
            proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro'
        }
    }
}

dependencies {
    api project(':modulea')
    api project(':moduleb')
    api project(':modulec')
    //调试优化 2
    if(!project.ext.isDebugModuleDebug) {
        api project(':debugmodule')
    }
}

//AndroidManifest.xml
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
    package="com.tomorrow.moduletest">
    <application
        android:name=".MainApplication"
        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=".MainActivity">
            <intent-filter>
                <action android:name="android.intent.action.MAIN" />
                <category android:name="android.intent.category.LAUNCHER" />
            </intent-filter>
        </activity>
    </application>
</manifest>

//PageConfig
public class PageConfig {
    private static final String ModuleAFragment = "com.tomorrow.modulea.ModuleAFragment";
    private static final String ModuleBFragment = "com.tomorrow.moduleb.ModuleBFragment";
    private static final String ModuleCFragment = "com.tomorrow.modulec.ModuleCFragment";

    private static final String BaseInit = "com.tomorrow.base.BaseInit";
    private static final String ModuleAInit = "com.tomorrow.modulea.ModuleAInit";

    public static String[] fragmentNames = {
            ModuleAFragment,
            ModuleBFragment,
            ModuleCFragment,
    };

    public static String[] initModules = {
            BaseInit,
            ModuleAInit,
    };
}

//MainApplication
public class MainApplication extends Application {
    private static final String TAG = "MainApplication";

    @Override
    public void onCreate() {
        super.onCreate();
        Log.d(TAG, "zwm, onCreate");
        initModules();
    }

    private void initModules() {
        Log.d(TAG, "zwm, initModules");
        for(String init : PageConfig.initModules) {
            try {
                Class<?> clazz = Class.forName(init);
                IBaseAppInit moduleInit = (IBaseAppInit) clazz.newInstance();
                moduleInit.onInit(this);
            } catch (ClassNotFoundException e) {

            } catch (IllegalAccessException e) {

            } catch(InstantiationException e) {

            }
        }
    }
}

//MainActivity
public class MainActivity extends AppCompatActivity {
    private static final String TAG = "MainActivity";
    private List<Fragment> mFragmentList = new ArrayList<>();
    private ViewPager mViewPager;
    private ViewPagerAdapter mViewPagerAdapter;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        Log.d(TAG, "zwm, onCreate");
        setContentView(R.layout.activity_main);
        initView();
    }

    private void initView() {
        Log.d(TAG, "zwm, initView");
        try {
            for(String address : PageConfig.fragmentNames){
                Class clazz = Class.forName(address);
                Fragment item = (Fragment) clazz.newInstance();
                mFragmentList.add(item);
            }
        }catch (ClassNotFoundException e){

        }catch (IllegalAccessException e){

        }catch (InstantiationException e){

        }

        mViewPager = findViewById(R.id.view_pager);
        mViewPagerAdapter = new ViewPagerAdapter(getSupportFragmentManager(), mFragmentList);
        mViewPager.setAdapter(mViewPagerAdapter);
        mViewPager.setOffscreenPageLimit(3);
    }
}

//activity_main.xml
<?xml version="1.0" encoding="utf-8"?>
<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="match_parent">
    <androidx.viewpager.widget.ViewPager
        android:id="@+id/view_pager"
        android:layout_width="match_parent"
        android:layout_height="match_parent"/>
</FrameLayout>

//ViewPagerAdapter
public class ViewPagerAdapter extends FragmentPagerAdapter {
    private static final String TAG = "ViewPagerAdapter";
    public List<Fragment> fragmentList;

    public ViewPagerAdapter(FragmentManager fm, List<Fragment> fragmentList) {
        super(fm);
        this.fragmentList = fragmentList;
    }

    @Override
    public Fragment getItem(int arg0) {
        return fragmentList.get(arg0); //显示第几个页面
    }

    @Override
    public int getCount() {
        return fragmentList.size(); //有几个页面
    }
}

5.业务组件:ModuleA

//build.gradle
apply from: "${rootProject.rootDir}/common_config.gradle"
project.ext.setLibDefaultConfig project

android {
    defaultConfig {
        versionCode 1
        versionName "1.0"

        consumerProguardFiles 'consumer-rules.pro'
    }

    buildTypes {
        release {
            minifyEnabled false
            proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro'
        }
    }

}

dependencies {
    api project(':base')
}

//AndroidManifest.xml
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
    package="com.tomorrow.modulea" >
    <uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE"/>
</manifest>

//ModuleAInit
public class ModuleAInit implements IBaseAppInit {
    private static final String TAG = "ModuleAInit";

    @Override
    public void onInit(Application application) {
        Log.d(TAG, "zwm, onInit, application: " + application);
    }
}

//ModuleAFragment
public class ModuleAFragment extends Fragment {
    private static final String TAG = "ModuleAFragment";

    @Nullable
    @Override
    public View onCreateView(@NonNull LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) {
        Log.d(TAG, "zwm, onCreateView");
        View view = inflater.inflate(R.layout.fragment_modulea,container,false);
        return view;
    }

    @Override
    public void onActivityCreated(@Nullable Bundle savedInstanceState) {
        super.onActivityCreated(savedInstanceState);
        Log.d(TAG, "zwm, onActivityCreated");
        new Handler().postDelayed(new Runnable() {
            @Override
            public void run() {
                Log.d(TAG, "zwm, EventBus post event");
                TestEvent event = new TestEvent("Event From ModuleA");
                EventBus.getDefault().post(event);
            }
        }, 2000);

        new Handler().postDelayed(new Runnable() {
            @Override
            public void run() {
                Log.d(TAG, "zwm, ARouter start navigation");
                ARouter.getInstance().build("/test/activity").navigation();
            }
        }, 4000);

        new Handler().postDelayed(new Runnable() {
            @Override
            public void run() {
                Log.d(TAG, "zwm, GreenDao CRUD");
                User user = new User();
                user.setName("Tomy");
                user.setAge("30");
                user.setContent("Android");
                BaseInit.getInstance().getDaoSession().insert(user);
                Log.d(TAG, "zwm, insert name: Tomy, age: 30, content: Android");
                List<User> users = BaseInit.getInstance().getDaoSession().loadAll(User.class);
                for(User item : users) {
                    Log.d(TAG, "zwm, query id: " + item.getId() + ", name: " + item.getName() + ", age: " + item.getAge() + ", content: " + item.getContent());
                }
            }
        }, 6000);

        new Handler().postDelayed(new Runnable() {
            @Override
            public void run() {
                Log.d(TAG, "zwm, PermissionSDK");
                if(PermissionUtil.checkSelfPermission(getContext(), Manifest.permission.READ_EXTERNAL_STORAGE)) {
                    Log.d(TAG, "zwm, READ_EXTERNAL_STORAGE permission get");
                } else {
                    Log.d(TAG, "zwm, READ_EXTERNAL_STORAGE permission not get");
                }
            }
        }, 8000);
    }
}

//fragment_modulea.xml
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent">
<TextView
    android:layout_width="wrap_content"
    android:layout_height="wrap_content"
    android:layout_centerInParent="true"
    android:text="This is ModuleA Fragment"/>
</RelativeLayout>

6.业务组件:ModuleB

//build.gradle
apply from: "${rootProject.rootDir}/common_config.gradle"
project.ext.setLibDefaultConfig project

android {
    defaultConfig {
        versionCode 1
        versionName "1.0"

        consumerProguardFiles 'consumer-rules.pro'
    }

    buildTypes {
        release {
            minifyEnabled false
            proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro'
        }
    }

}

dependencies {
    api project(':base')
}

//AndroidManifest.xml
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
    package="com.tomorrow.moduleb" />
    
//ModuleBFragment
public class ModuleBFragment extends Fragment {
    private static final String TAG = "ModuleBFragment";

    @Nullable
    @Override
    public View onCreateView(@NonNull LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) {
        Log.d(TAG, "zwm, onCreateView");
        View view = inflater.inflate(R.layout.fragment_moduleb,container,false);
        return view;
    }

    @Override
    public void onActivityCreated(@Nullable Bundle savedInstanceState) {
        super.onActivityCreated(savedInstanceState);
        Log.d(TAG, "zwm, onActivityCreated, EventBus register");
        EventBus.getDefault().register(this);
    }

    @Override
    public void onDestroy() {
        super.onDestroy();
        Log.d(TAG, "zwm, onDestroy, EventBus unregister");
        EventBus.getDefault().unregister(this);
    }

    @Subscribe
    public void onEvent(TestEvent event){
        Log.d(TAG, "zwm, EventBus onEvent msg: " + event.getMsg() + ", thread: " + Thread.currentThread().getName());
    }
}

//fragment_moduleb.xml
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="match_parent">
    <TextView
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_centerInParent="true"
        android:text="This is ModuleB Fragment"/>
</RelativeLayout>

7.业务组件:ModuleC

//build.gradle
apply from: "${rootProject.rootDir}/common_config.gradle"
project.ext.setLibDefaultConfig project

android {
    defaultConfig {
        versionCode 1
        versionName "1.0"

        consumerProguardFiles 'consumer-rules.pro'
    }

    buildTypes {
        release {
            minifyEnabled false
            proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro'
        }
    }

}

dependencies {
    api project(':base')
}

//AndroidManifest.xml
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
    package="com.tomorrow.modulec">
    <application>
        <activity android:name=".ModuleCActivity"/>
    </application>
</manifest>

//ModuleCFragment
public class ModuleCFragment extends Fragment {
    private static final String TAG = "ModuleCFragment";

    @Nullable
    @Override
    public View onCreateView(@NonNull LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) {
        Log.d(TAG, "zwm, onCreateView");
        View view = inflater.inflate(R.layout.fragment_modulec,container,false);
        return view;
    }
}

//fragment_modulec.xml
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="match_parent">
    <TextView
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_centerInParent="true"
        android:text="This is ModuleC Fragment"/>
</RelativeLayout>

//ModuleCActivity
@Route(path = "/test/activity")
public class ModuleCActivity extends AppCompatActivity {
    private static final String TAG = "ModuleCActivity";

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        Log.d(TAG, "zwm, onCreate");
        setContentView(R.layout.activity_modulec);
    }
}

//activity_modulec.xml
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="match_parent">
    <TextView
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_centerInParent="true"
        android:text="This is ModuleC Activity"/>
</RelativeLayout>

8.业务组件:DebugModule

//build.gradle
apply from: "${rootProject.rootDir}/common_config.gradle"
//调试优化 3
if(!project.ext.isDebugModuleDebug){
    project.ext.setLibDefaultConfig project //当前为lib
} else{
    project.ext.setAppDefaultConfig project //当前为app
}

android {
    defaultConfig {
        versionCode 1
        versionName "1.0"

        consumerProguardFiles 'consumer-rules.pro'
    }

    buildTypes {
        release {
            minifyEnabled false
            proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro'
        }
    }

    //调试优化 4
    sourceSets {
        main {
            if (project.ext.isDebugModuleDebug) {
                manifest.srcFile 'src/main/debug/AndroidManifest.xml'
            } else {
                manifest.srcFile 'src/main/release/AndroidManifest.xml'
            }
        }
    }
}

dependencies {
    api project(':base')
}

//src/main/release/AndroidManifest.xml
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
    package="com.tomorrow.debugmodule" />
    
//src/main/debug/AndroidManifest.xml
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
    package="com.tomorrow.debugmodule">
    <application
        android:label="@string/app_name"
        android:theme="@style/Theme.AppCompat.Light">
        <activity android:name=".DebugModuleActivity">
            <intent-filter>
                <action android:name="android.intent.action.MAIN" />
                <category android:name="android.intent.category.LAUNCHER" />
            </intent-filter>
        </activity>
    </application>
</manifest>

//DebugModuleActivity
public class DebugModuleActivity extends AppCompatActivity {
    private static final String TAG = "DebugModuleActivity";

    @Override
    protected void onCreate(@Nullable Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        Log.d(TAG, "zwm, onCreate");
        setContentView(R.layout.activity_debugmodule);
    }
}

//activity_debugmodule.xml
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="match_parent">
    <TextView
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_centerInParent="true"
        android:text="This is DebugModule Activity"/>
</RelativeLayout>

9.基础组件:Base

//build.gradle
apply from: "${rootProject.rootDir}/common_config.gradle"
project.ext.setLibDefaultConfig project

android {
    defaultConfig {
        versionCode 1
        versionName "1.0"
        consumerProguardFiles 'consumer-rules.pro'
    }

    buildTypes {
        release {
            minifyEnabled false
            proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro'
        }
    }

}

dependencies {
    //EventBus
    api 'org.greenrobot:eventbus:3.0.0'
    //ARouter 3
    api'com.alibaba:arouter-api:1.5.0'
    //GreenDao 4
    api 'org.greenrobot:greendao:3.2.2'
    //PermissionSDK
    api project(':permission')
}

//GreenDao 5
greendao {
    schemaVersion 1 //指定数据库版本号,更新操作会用到
    daoPackage 'com.tomorrow.base.db.greendao' //自动生成的dao的包名,包名默认是entity所在的包
    targetGenDir 'src/main/java' //生成数据库文件的目录
}

//AndroidManifest.xml
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
    package="com.tomorrow.base" />

//src/main/java/com.tomorrow.base/IBaseAppInit.java
public interface IBaseAppInit {
    void onInit(Application application);
}

//src/main/java/com.tomorrow.base/BaseInit.java
public class BaseInit implements IBaseAppInit {
    private static final String TAG = "BaseInit";
    private static BaseInit mInstance;
    private Application mApplication;
    private DaoSession mDaoSession;

    public static BaseInit getInstance() {
        return mInstance;
    }

    @Override
    public void onInit(Application application) {
        Log.d(TAG, "zwm, onInit, application: " + application);
        mInstance = this;
        mApplication = application;
        Log.d(TAG, "zwm, init ARouter");
        ARouter.init(application);
        initGreenDao();
    }

    private void initGreenDao() {
        Log.d(TAG, "zwm, init GreenDao");
        DaoMaster.DevOpenHelper helper = new DaoMaster.DevOpenHelper(mApplication.getApplicationContext(), "tomorrow.db");
        SQLiteDatabase db = helper.getWritableDatabase();
        DaoMaster daoMaster = new DaoMaster(db);
        mDaoSession = daoMaster.newSession();
    }

    public DaoSession getDaoSession() {
        return mDaoSession;
    }
}

//src/main/java/com.tomorrow.base/event/TestEvent.java
public class TestEvent {
    private String msg;

    public TestEvent(String msg) {
        this.msg = msg;
    }

    public String getMsg(){
        return msg;
    }
}

//src/main/java/com.tomorrow.base/db/User.java
@Entity
public class User {
    @Id(autoincrement = true)
    private Long id; //主键,自增长
    @NotNull
    private String name; //名称,不允许为空
    private String age;
    private String content;
    @Generated(hash = 1079760932)
    public User(Long id, @NotNull String name, String age, String content) {
        this.id = id;
        this.name = name;
        this.age = age;
        this.content = content;
    }
    @Generated(hash = 586692638)
    public User() {
    }
    public Long getId() {
        return this.id;
    }
    public void setId(Long id) {
        this.id = id;
    }
    public String getName() {
        return this.name;
    }
    public void setName(String name) {
        this.name = name;
    }
    public String getAge() {
        return this.age;
    }
    public void setAge(String age) {
        this.age = age;
    }
    public String getContent() {
        return this.content;
    }
    public void setContent(String content) {
        this.content = content;
    }
}

//src/main/java/com.tomorrow.base/db/greendao/
DaoMaster、DaoSession、UserDao

10.功能组件:PermissionSDK

//build.gradle
apply plugin: 'com.android.library'

android {
    compileSdkVersion 29
    buildToolsVersion "29.0.0"


    defaultConfig {
        minSdkVersion 15
        targetSdkVersion 29
        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'
        }
    }

}

dependencies {
    implementation fileTree(dir: 'libs', include: ['*.jar'])

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

//AndroidManifest.xml
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
    package="com.tomorrow.permission" />

//PermissionUtil
public class PermissionUtil {
    private static final String TAG = "PermissionUtil";

    public static boolean checkSelfPermission(Context context, String permission) {
        boolean exist = false;
        if(ContextCompat.checkSelfPermission(context, permission) == PackageManager.PERMISSION_GRANTED) {
            exist = true;
        }
        Log.d(TAG, "zwm, checkSelfPermission: " + permission + ", exist: " + exist);
        return exist;
    }
}

相关文章

  • Android组件化方案

    Android组件化方案Android彻底组件化demo发布

  • CTMediator路由swift

    接着上篇组件化的demo,在demo中借助CTMediator实现各个功能块间的调用 路由?组件化? 组件化是将A...

  • 组件化 -- Demo

    功能 版本参数优化:common_config.gradle 动态创建Fragment:ViewPager+Fra...

  • 组件化demo

    1. 环境准备 1.1创建相关组件 MainApp — appModule A — LoginComponent ...

  • ARetrofit

    Android组件化超级路由,为简单而生。 Github 源码: ARetrofit demo demo apk ...

  • ARetrofit - Android组件化最佳路由

    Android组件化最佳路由,为简单而生。 Github 源码: ARetrofit demo demo apk ...

  • iOS组件化 - subspec子库的制作

    本文章用到的demo的下载地址 关于组件化前几篇文章请查看这里iOS组件化(上篇)- 拆分基础组件iOS组件化(中...

  • vue组件化案例

    简单的vue 组件化demo,效果很简单,就是一个列表增删改查。 未组件化代码: 效果: 组件化后: 效果: 详细...

  • Android组件化专题 - 组件化配置

    demo地址 Android组件化专题,详细讲解组件化的使用及配置,以及实现的原理。 本文章讲解了组件化的由来及配...

  • Android MVVM+Retrofit+协程实践

    附上demo链接MVVM+Retrofit+协程组件化项目 本文用到的组件: ViewModel LiveData...

网友评论

    本文标题:组件化 -- Demo

    本文链接:https://www.haomeiwen.com/subject/amunfhtx.html