如何设计C/S架构的Android SDK | 3. 如何设计一个稳定的服务?

81 阅读2分钟

开启掘金成长之旅!这是我参与「掘金日新计划 · 2 月更文挑战」的第 8 天,点击查看活动详情

服务端负责分配资源,并支持多个客户端同时请求,需保证充分稳定。

设计原则

  • 保证时序性

    一个服务端同时可能收到多个客户端的请求,实现时需要确保服务端有序、正确地为每个客户端返回对应的结果。

  • 保证稳定性

    服务端应该有健壮的容错机制和异常处理机制,不应该因为客户端的参数异常、调用顺序异常导致服务端内部出现异常,并影响其他客户端的调用结果。

基本流程

  1. 定义功能抽象层,面向接口编程

    首先,我建议 API层服务端 的方法都基于同一个接口实现。举个例子,SDK准备对外提供一个打印的方法 print 方法,客户端通过PrinterManager类对外提供打印方法,服务端的实现是 PrintService

    // 统一接口定义
    public interface Printer {
        void print();
    }
    
    // API层的方法实现,供客户端调用的方法
    public class PrintManager implements Printer{
        void print(){
            // TODO 通过IPC调用发送请求至服务端
        }
    }
    
    // 服务端的方法实现,真正实现打印的地方
    public class PrintService implements Printer{
       // 对于服务端来讲,可能有不同的几种实现方案,这里也通过具体的委托类来实现
       // 每一个具体实现类也都是基于Printer实现
       Printer printer = new PrinterImpl();     
       void print(){
           // TODO 执行真正的打印操作
           printer.print();
       }
    }
    
    

    服务端是接口功能的真正实现的地方,可能也会多种不同的实现方案,例如:不同的硬件设备接入了不同的打印机,会使用不同的打印机SDK。

    定义通用的接口,保证了方法、参数的一致性,可以扩展接入更多的实现的同时,也不影响原有的逻辑架构。

  2. 有序管理客户端请求,确保线程安全,合理分配资源

    服务端可以同时接收多个客户端,或者一个客户端的多次请求。服务端需要保证每个请求之间不受影响,对于共享或全局变量的变更需要做同步处理。

    对于独占性资源,可以根据业务需求设置 排队等待立即抢占超时丢弃 等策略来管理请求。

    RemoteCallbackList可以管理客户端的Binder回调,并且提供了onCallbackDied 回调方法,在客户端Binder死亡发生调用,可以进行资源的回收操作。

  3. 当变更接口时,需要保证兼容性

    当SDK正式发布后,后续迭代的版本原则上不应该删除已有的API,也不应该改变API的返回值和参数定义。

    使用AIDL新增接口时,在.aidl文件末尾依次添加。