安卓资源收集

组件化解耦,SCM

2018-08-21  本文已影响66人  半只温柔

SCM - 组件化通信工具

一切皆组件,当每个组件可看成一个微服务,组件化项目才会真正解耦

组件化介绍:

通过一个类比的例子来介绍组件化
随着业务的复杂度增大,业务线纵横交错,往往牵一发而动全身。
我们希望业务代码也能像一部智能手机。
入口模块:应用桌面图标,更像是home模块,只提供入口;
业务模块:通过appstore,下载我们需要的app,每个app(模块)职责分明,闹钟,短信,电话......;
当某个模块需求变化,并不想影响到其他业务线的大规模变动,只用更新当前app(模块);
甚至 -- 我的模块、组件可以发到 appstore 给其他手机使用(插件化),每个应用可以资源互动(组件通信),可以增量更新…
所以:
一切皆组件,
每个模块就是一个微服务,通过 rest api 来访问,用完即走。

SCM介绍:

SCM就是用来定义api接口(通过注解在编译期生成服务注册表),通过请求(SCM.req),来拿到对应服务(action)的响应结果(ScCallback)的工具

SCM 不支持 Install Run

1: 通过注解注册 @Action(name = "") 声明服务 类实现ScAction

2: 一个 Action 对应一个微服务

3: 通过对注解 Compiler 编译期生成 -> 服务注册表

4: Application 初始化 运行期扫描服务、缓存注册表

5: 调用 SCM.req(String action,Callback A) 调用服务, 真正实现解耦

action ---> module actionTable ---> scmTable


SCM.png

使用:

1:根项目root-project的build.gradle

repositories {
        ...
        maven {
            url  "https://dl.bintray.com/woaigmz/SCM"
        }
    }

2:你的每个module的build.gradle

defaultConfig {
        ...
        javaCompileOptions {
            annotationProcessorOptions {
                arguments = [KEY_MODULE_NAME:"Main"]
                includeCompileClasspath true
            }
        }
    }
...
dependencies {
    compile 'com.woaigmz.scm:scm-api:0.0.4'
    compile 'com.woaigmz.scm:scm-annotation:0.0.4'
    annotationProcessor 'com.woaigmz.scm:scm-compiler:0.0.4'
    }

3:初始化

public class App extends Application {
    @Override
    public void onCreate() {
        super.onCreate();
        //对应每个module的 arguments = [KEY_MODULE_NAME:"Main"]
        SCM.get().scanningSCMTable(new String[]{"Main", "Home"});
    }
}

4:定义 Service(@Action)为 module-home/actions/HomeLoadConfigAction,为 home-module 提供给外界的api

//home-module/actions/HomeLoadConfigAction 
@Action(name = "LoadConfig")
public class HomeLoadConfigAction implements ScAction {

    @Override
    public void invoke(Context context, String param, ScCallback callback) {
        //模拟加载网络数据
        DataProvider.getConfig(callback);
    }

}
//home-module/actions/HomeEntryAction 
@Action(name = "HomeEntry")
public class HomeEntryAction implements ScAction {

    @Override
    public void invoke(Context context, String param, ScCallback callback) {
        Intent intent = new Intent();
        intent.setClass(context, HomeActivity.class);
        context.startActivity(intent);
        callback.onCallback(true, "HomeEntryAction:我把HomeActivity打开了", "");
    }
}

//除页面跳转之外,大部分都是异步,业务情景不同,本框架不提供异步转同步,开发者自己实现
5:请求:由action-name通过 SCM.req()方法在module-app / MainActivity 获取 module-home/actions 下的服务action

private WeakHandler h = new WeakHandler(new Handler.Callback() {
        @Override
        public boolean handleMessage(Message msg) {
            String s = (String) msg.obj;
            Toast.makeText(MainActivity.this, s, Toast.LENGTH_SHORT).show();
            tvLoadConfig.setText(s);
            return false;
        }
    });
//通过Action :"LoadConfig"请求; 响应:ScCallback 返回的是子线程进行的网络请求结果要用handler
private void loadConfigByHomeModule() {
        try {
            SCM.get().req(MainActivity.this, "LoadConfig", new ScCallback() {
                @Override
                public void onCallback(boolean b, String data, String tag) {
                    if (b) {
                        Message obtain = Message.obtain();
                        obtain.obj = data;
                        if (h != null) {
                            h.sendMessage(obtain);
                        } else {
                            Toast.makeText(MainActivity.this, "WeakHandler has been Gc", Toast.LENGTH_SHORT).show();
                        }

                    }
                }
            });
        } catch (Exception e) {
            Log.e(Constants.SCM, e.getMessage());
        }
    }
//跳转到  Home-module/view/HomeActivity
try {
                SCM.get().req(MainActivity.this, "HomeEntry", new ScCallback() {
                    @Override
                    public void onCallback(boolean b, final String data, String tag) {
                        if (b)
                            Toast.makeText(MainActivity.this, data, Toast.LENGTH_SHORT).show();
                    }
                });
            } catch (Exception e) {
                Log.e(Constants.SCM, e.getMessage());
            }

想法:

想到 java 后台通过action来定义一个接口 ,servlet里的 req,res,有更好的欢迎issue,star fork 。。。
具体实现思路可用参考项目:SCM地址:
注解工具的作用:action 加到注册表,通过 annotationProcessor 编译时注解,编译期生成(SCMTable)表注册
注解工具链接:ActionProcessor.java
SCM优点:
1:跨进程,通过传递的 json/string 字符实现类似 CC 的通过socket协议传递字符流
2:通过action对应的name,反射调用Action的invoke方法,实现解耦合 类似组件化项目 ModularizationArchitecture (aidl + service跨进程)
3:注册表简洁易懂,想到了R文件的生成,public static final "$actionName" = "@action对应action的实际包名"
4:只要原来的协议不变(@action(name="XXX"))代码重构不会对action有影响
5:编译期生成SCMTable提高了扫描整个包的性能
maven上传命令:
gradle install / gradlew bintrayUpload 上传项目到 maven
查看有焦点的activity的包名
linux:adb shell dumpsys activity | grep "mFocusedActivity" / windows:adb shell dumpsys activity | findstr "mFocusedActivity"
不提供异步转通过方法,因为除了页面跳转,一般的action都是耗时操作,处理方式留给开发者具体问题具体对待,

几种异步转同步:
wait / notify
条件锁
Future
CountDownLatch/CyclicBarrier
Handler
信号量
上一篇下一篇

猜你喜欢

热点阅读