首先粘贴源码地址,欢迎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
2.单独编译组件化配置(gradle)
依赖关系
- 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配置:
//集成编译,打包为Library
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="component.android.com.home">
<application android:theme="@style/home_AppTheme">
<activity android:name=".view.activity.HomeActivity"/>
</application>
</manifest>
//单独编译,打包为单独Application 可单独编译
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="component.android.com.home">
<application
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">
<activity android:name=".view.activity.HomeActivity">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
</application>
</manifest>
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就实现了一个简单的交互逻辑
首先开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