45 SPI(面向接口编程)-服务分发

作者: 凤邪摩羯 | 来源:发表于2022-02-17 09:15 被阅读0次

    Android端简单易用的SPI框架2 — SPA服务分发

    上一篇文章已经给大家讲解了SPA的基本功能和基础用法,那SPA到底能做用来做什么呢,可能大家到目前为止还是觉得很模糊。其实SPA是一个最基础、最底层的SPI框架,他只负责跨模块创建对象,并对创建出的对象、和对象方法进行灵活管理,从而避免不必要的模块依赖,降低模块之间的耦合性。我们可以在它基础上开发任何你需要的组件,典型如路由、事件分发、服务分发等等。 那么本文将以混合开发过程涉及到的桥接事件分发为例子,给大家说一说SPA到底可以做什么!

    无论是Flutter、ReactNative还是H5方式的混合开发,原生端与混合端都少不了信息交互,我们通常叫做桥接。那么您的项目是如何将混合端发过来的桥接事件发送到各个模块的呢?

    下面介绍一下项目中如何使用SPA来做这样的桥接事件分发工作的。先看一下下面这张示意图:

    image.png
    • 最上面是混合端,我的项目中Flutter, RN和H5三个混合方式共存,以RN和H5为主
    • 中间是桥接协议,我为不同的混合方式定义了相同的桥接协议,这样我只需要一套解析方式
    • 最下面的原生端,原生端有很多的业务模块和很多的功能模块;
    • 所有的事件通过BridgeDispatcher分发给各个模块, BridgeDispatcher是基于SPA一个具体实现

    这样处理的好处是混合模块只需要依赖桥BridgeDispatcher分发服务,完全不需要依赖任何原生模块。从而将混合模块和原生模块完全解耦合。原生模块也可以剥离混合模块独立运行,也可以加入混合模块完整运行,从而达到热插拔的效果!

    下面我们看看本文的重点: ** BridgeDispatcher是如何实现的? SPA在这里扮演的是怎样的角色?**

    讲解BridgeDispatcher之前有必要先讲解一下这里的桥接协议

    • 桥接协议是通过json格式在混合端和原生端传输的;
    • 协议格式: {"group":"your group", "id":"your id", "args":{"k1","v1", "k2",v2 ....}}
    • group: 分组, 协议用group + id来定义一个path,group的文档意义大于实际意义
    • id: id, 协议用group + id来定义一个path
    • args: 桥接参数, BridgeDispatcher会通过泛型将args转换成map或javaBean对象
    • 分发回调及返回参数不再介绍,感兴趣请查看用例代码

    ** 下面正式介绍BridgeDispatcher ** BridgeDispatcher有一个Execution接口

    public interface Execution {
        void create(Activity activity, IBridgeRequest request, BridgeCallback callback);
        void execute(Gson gson);
        void destroy();
    }
    
    复制代码
    

    Execution接口有他的基础实现类,他有同步和异步两种执行方式,分别对应SyncExecution和AsyncExecution,这里以SyncExecution为例。 他主要作用是将json格式的参数解析成泛型参数T,并使用同步方式抛给子类去实现具体的业务细节。

    public abstract class SyncExecution<T> extends BaseExecution<T> {
    
        ....
    
        @Override
        public void execute(final Gson gson) {
            mMainHandler.post(new Runnable() {
                @Override
                public void run() {
                    try {
                        onExecution(parseArgs(gson), new BridgeCallback() {
                             @Override
                            public void success(BridgeResult result) {
                                sendResolveMessage(result); //回传给混合端
                            }
    
                            ....
                        });
                        destroy();
                    } catch (Throwable e) {
                        rejectByException(e);
                    }
                }
            });
        }
    
        protected abstract void onExecution(T t, BridgeCallback callback);
    
        ......
    }
    复制代码
    

    最后SPA通过path跨模块查找处在各个模块的Executions, 最后执行Execution

    // IBridgeRequest是对桥接参数的封装,包含group, id, args等参数
    public static void messageToApp(Activity activity, IBridgeRequest routerParam, BridgeCallback callback) {
            try {
                IService service = Spa.getService(routerParam.getPath()); // SPA通过path跨模块获取实现类对象。
                if (service instanceof Execution) {
                    Execution execution = (Execution) service;
                    execution.create(activity, routerParam, callback);
                    execution.execute(gson);
                } else {
                    BridgeResult result = new BridgeResult();
                    result.setCode(0);
                    result.setMessage("unknown path");
                    if (callback != null) {
                        callback.failed(result);
                    }
                }
            } catch (Throwable e) {
                e.printStackTrace();
            }
        }
    复制代码
    

    举个栗子🌰, 混合端想获取存储在原生端的app版本名称,根据桥接协议,它传给原生的参数为

    {"group":"storage", "id":"get", "args":{"key":"versionName"}}
    复制代码
    

    原生端只需要在storage模块定义一个StorageExecution,代码如下:

    @Service(path = "/storage/get")
    public class StorageExecution extends MapStringSyncExecution<String> {
        public void onExecution(String key, BridgeCallback callback) {
            StorageService storageService = Spa.getService(StorageService.class); //假设有个StorageService可以获取存储内容
            String versionName = storageService.get(key); //key的值为versionName
            callback.sucess(versionName); //verionName为1.0.0   将1.0.0这个版本名称返回给BridgeDispatcher,再由 BridgeDispatcher回传给混合端
        }
    }
    复制代码
    

    整个事件分发的过程,SPA起到的是桥梁的作用。是SPA将混合端桥接协议和原生桥接实现联系在一起,从而实现了混合端和原生端的完全解耦。

    不仅仅是桥接事件的分发,当我们把一个个分发的事件看做是一个个的服务。我们可以从各个维度利用他们,如Schema路由、CommandLine解析指令,我们可以对上面的示意图进一步扩展。


    image.png

    服务分发相关示例源码由于特殊原因不能直接分享出来,感兴趣可以联系我私发给您

    总结

    服务分发是SPA框架的一个典型应用场景,主要涉及到还是SPA的最基础的跨模块创建对象的能力,后续进阶篇会讲解基于SPA开发的SPRouter路由, 给大家介绍一下SPA的拦截策略和拦截能力

    相关文章

      网友评论

        本文标题:45 SPI(面向接口编程)-服务分发

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