[关闭]
@zhuhf 2018-01-16T15:00:19.000000Z 字数 2561 阅读 965

金诚逸模块之间交互规范 - 初稿


目的

旨在规范各个子模块(子工程)对外暴露 数据、UI 的方式,提供统一的接口和编码实现。

现状

  1. 暴露数据的方式
    将接口定义到 common 模块,具体实现放在各自的模块内。依赖 ARouter 的服务实现方式,调用各个模块提供的服务。
  2. 暴露UI的方式
    同样使用 ARouter 的解决方案,对 Activity 注解对应的路径,实现跨模块的UI跳转。

存在的问题

暴露数据的方式是合理的,因为对外只在 common 模块暴露了接口的定义。

而暴露 Activity,需要将对应的 path 下沉到 common 模块,各个子模块使用 ARouter 结合对应的 path,跳转到对应的界面,并传递数据。

为了提高编码效率,通常会统一将所有需要暴露的 Activity 的跳转方法写到 ActivityLauncher 中,采取集中管理的方式,这种方式存在以下几个问题:

  1. 这种方式导致了 ActivityLauncher 的急剧膨胀,截止目前已经有超过 2400+ 行代码,随着业务的增长,这个类的增长将是不可控的。

  2. 另外,模块内部的 UI 跳转,到底是使用 Android 自带的 Intent 方式,还是使用 ARouter 来处理?没有一个明确的说词,经常取决于编码代码的人的习惯。

解决方案

原则:高内聚、低耦合,针对接口编程而不是实现。

子模块只对外暴露对应的接口,如何实现属于内部细节,外部不需要了解。

具体编码原则

  1. Activity 提供静态跳转方法入口,内部用 Intent 还是 ARouter 不做限制,但如果使用 ARouter,对应的 path 请放在自己的模块,因为外部不需要知道

    @Route(path = AtnOrderDetailActivity.PATH)
    public class AtnOrderDetailActivity extends BasicActivity {
        /**
         * path 定义
         */
        static final String PATH = "/Auction/AtnOrderDetailActivity";
    
        public static void start(Context activity, String orderNo) {
            ARouter.getInstance().build(PATH)
                .withString("orderNo", orderNo)
                .navigation(activity);
        }
    
        public static void start(Context activity, String orderNo) {
            Intent intent = new Intent(activity, AtnOrderDetailActivity.class);
            intent.putExtra("orderNo", orderNo);
            activity.startActivity(intent);
        }
    }
    

    以上两种实现都是 OK 的。

  2. 模块对外暴露的 数据、UI,定义在 common 模块的服务接口

    public interface ModuleAuctionService extends SchemeProvider {
        /**
         * 订单详情
         * @param orderNo 订单号
         */
        @UiThread
        void gotoOrderDetail(Context activity, String orderNo);
    }
    
  3. 服务的具体实现放在各自模块

    @Route(path = IntentPath.SERVICE_AUCTION)
    public class ModuleAuctionServiceImpl implements ModuleAuctionService {
    
        // ...
    
        @Override
        public void gotoOrderDetail(Context activity, String orderNo) {
            AtnOrderDetailActivity.gotoAuctionOrderDetail(orderNo);
        }
    }
    

    这里需要提一下,gotoOrderDetail 内部仍然要使用对应的 Activity 的静态方法去跳转。

  4. Scheme 处理器
    同样,也是属于内部模块,也要使用 Activity 的静态方法去跳转。

    public class AtnSchemeProcessor implements IProcessor {
    
        static final String JCY_AUCTION_DETAIL = "JCY_Auction_Detail";
    
        public String[] getAction() {
            return new String[]{JCY_AUCTION_DETAIL};
        }
    
        @Override
        public boolean handleScheme(FragmentActivity activity, @NonNull String schemeUrl, @NonNull String action, Map<String, String> params) {
            switch (action) {
                case JCY_AUCTION_DETAIL:
                    if (!Utils.checkLogin(activity, schemeUrl)) {
                        return true;
                    } else {
                        String auctionId = params.get("auctionId");
                        AuctionDetailActivity.actionStart(activity, auctionId);
                    }
                    break;
            }
            return true;
        }
    }
    
  5. 服务使用方式

    ModuleAuctionService service = ServiceLauncher.getServiceByName(IntentPath.SERVICE_AUCTION);
    if (service != null) {
        service.gotoOrderDetail(this, orderNo);
    }
    

    目前 ServiceLauncher 的做法是:包装了一层方法,供外部调用。
    个人觉得有点冗余了,为了避免 ServiceLauncher 走上 ActivityLauncher 的老路,建议大家不要去这么做了。


遵循以上几个原则之后,原有 ActivityLauncher 的所有方法,被分别移到了各个子模块中去。

如果需要查询某个子模块对对外暴露的方法,只需要去 common 模块查看对应的接口定义就好了

模块对外接口定义,详见 module_commonlib 模块 service 包。

添加新批注
在作者公开此批注前,只有你和作者可见。
回复批注