android组件化解耦,Android组件化----完全解耦实践方案<一>

首先粘贴源码地址,欢迎frok,欢迎start

源码地址

目前,Android 组件化普遍使用于移动开发,但是组件化的初衷是为了解耦代码,并行开发效率;小型app似乎会care不到,完全解耦的组件化会在app越来越臃肿的时候带来很大的提升;

1.组件化介绍

ok,那么我们需要知道完全解耦的组件化框架应该注意哪些点:

主app只加载业务组件,不可调用组件;组件与组件之间不存在调用关系;这样无论是主app和业务组件都是完全独立,完全解耦的;

主app和组件都依赖common组件,通过common的注册和分发实现组件之间的交互,这个common我们姑且叫做业务主线

android中page使用common下层接口和路由进行实现(在本框架中,ARouter实现Activity跳转,ARouter-Interceptor实现Activity跳转的拦截;Fragment通过common下沉注册分发实现Fragment的填充)

每一个组件应当是一个app可单独编译:Library和Application之间转化使用gradle配置相应的Manifest和applicationId

b9766b1a9c31

component.jpg

2.单独编译组件化配置(gradle)

b9766b1a9c31

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配置:

b9766b1a9c31

1.png

//集成编译,打包为Library

package="component.android.com.home">

//单独编译,打包为单独Application 可单独编译

package="component.android.com.home">

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">

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就实现了一个简单的交互逻辑

b9766b1a9c31

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.DEBUG){

//打印日志

ARouter.openLog();

ARouter.openDebug();

}

ARouter.init(this);

ComponentServiceFactory.getInstance(this).setHomeFragmentService(new HomeFragmentService());

}

@Override

public void initMoudleData(Application application) {

}

}

在App中调用:

app-MainActivity:

private void initBaseView() {

FragmentManager supportFragmentManager = getSupportFragmentManager();

ComponentServiceFactory.getInstance(this)

.getHomeFragmentService().newFragment(this,R.id.content,supportFragmentManager,null,null);

}

这样一个home组件中的homeFragment就加载到主app的xml中

同理组件之间的fragment引用亦如此

注意框架中component-IFragmentService实现了两个方法:

//获取目标的fragment来进行操作

Fragment getFragment(String tag);

//用于固定的区域来填充相应fragment

void newFragment(Activity activity, int resId, FragmentManager fragmentManager, Bundle bundle, String tag);

getFragment(String tag);为获取目标fragment接口,获取到实例之后开发者自己实现fragment相关逻辑

newFragment(...);适用于在布局中静态添加fragment,一步到位

当然框架中还有部分限制组件资源的gradle配置,有兴趣可以在github下载demo

源码地址

感谢阅读 欢迎github star

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值