Skip to content

3. Remote

gaowei edited this page Nov 15, 2022 · 16 revisions

进程间通信

功能特点

  • 无需写aidl文件
  • 支持跨app
  • 使用方式几乎等同本地导航Router请求和Service请求,只需增加一些配置即可
  • 不需要异步去bindService等待结果,属于同步调用
  • 关于反射,服务端执行@Remote注解声明的方法时,无反射
  • 支持任意类型的对象跨进程传递,包括自定义类 (建议实现Parcelable,默认使用Gson序列化)
  • 服务端进程不存活,也会自动拉起并执行

基本使用方式

服务端进程

  • 配置服务端manifest,引入一个Provider组件,并指定authority
// 继承RemoteProvider自定义Provider类,一个进程对应一个唯一的Provider类
public class MyProvider extends RemoteProvider {
}

// 客户端Manifest定义(仅跨app调用时需要定义,android11以上系统对ContentProvider的要求)
<manifest>
    <queries>
        // 值是服务端进程cp的authority
        <provider android:authorities="com.server.authority" />
    </queries>
    <application>
        ...
<manifest>

// 服务端Manifest定义
<application>
    <provider
        // 自定义该进程的authority
        android:authorities="com.server.authority"
        // 使用RemoteProvider子类
        android:name="com.my.MyProvider"
        // 指定服务端进程名
        android:process="..." 
        // 如果允许其他app访问设置true
        android:exported="false" />
</application>
服务端目标是RouterHandler
@Router(scheme = "didi", host = "router", path = "/p")
public class SendOrderHandler implements IRouterHandler {
    @Override
    public void handle(@NonNull Request request, @NonNull Result result);
    }
}
服务端目标是Service
  • 方法执行默认使用反射的形式执行跨进程方法
  • 引入@Remote声明在跨进程的方法上,会自动生成本地代码,替代反射跨进程执行
  • @Remote支持任何对象类型,因Javassist的限制仅支持基本类型的包装类
  • 仅当跨app时需要注意不要被混淆,同一个app内无需担心混淆
@Service(function = IOrderService.class)
public class OrderService implements IOrderService {
    @Remote   // 此注解会自动生成本地代码,替代反射
    public void handle(String s, Integer i) {
    }
}

客户端进程

  • 使用方式基本同调用本地组件,仅需要setRemoteAuthority传入自定义的authority即可
// 调用远程RouterHandler
DRouter.build("didi://router/p")
        .setRemoteAuthority("com.server.authority")
        .start(context);
    
// 调用远程Service
DRouter.build(IServiceTest.class)
        .setRemoteAuthority("com.server.authority")
        .getService()            //构造方法
        .handle("name", 1);      //目标方法

扩展功能

IRemoteCallback

  • 方法参数可以使用IRemoteCallback作为回调对象,此类支持跨进程callback回来
  • 可以像普通的本地监听者模式一样,保存下来,完全忽略跨进程的背景
  • 支持泛型
// 服务端Service
@Service(function = IOrderService.class)
public class OrderService implements IOrderService {

	private Set<IRemoteCallback> callbacks = 
	    Collections.newSetFromMap(new ConcurrentHashMap<IRemoteCallback, Boolean>());
    @Remote
    public void register(IRemoteCallback.TypeN<X> callback) {
        callbacks.add(callback);
    } 
    @Remote
    public void unregister(IRemoteCallback.TypeN<X> callback) {
        callbacks.remove(callback);
    }

    public void callback(...) {
        for (IRemoteCallback.TypeN<X> instance : callbacks) {
            instance.callback(...);
        }
    }

自动重连

  • 当服务进程死亡以后,客户端可以等服务端被外力拉起后自动重连,重新执行一遍所有的方法
  • 使用生命周期来停止自动重连机制
  • 考虑到服务端可能是启动崩溃,所以暂时没有去支持由客户端主动去把死亡的服务端拉起
public class RemoteActivity extends AppCompatActivity {
    private IRemoteRegister registerInstance;
    private RouterLifecycle lifecycle = new RouterLifecycle();

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        IRemoteRegister registerInstance = 
            DRouter.build(IRemoteRegister.class)
                .setRemoteAuthority("com.server.authority")
                .setRemoteDeadResend(Extend.Resend.WAIT_ALIVE)
                .setLifecycleOwner(lifecycle)
                .getService();
    }

    @Override
    protected void onResume() {
        super.onResume();
        lifecycle.create();
        registerInstance.register(callback);
    }

    @Override
    protected void onStop() {
        super.onStop();
        lifecycle.destroy();
        registerInstance.unregister(callback);
    }

    private IRemoteCallback callback = new IRemoteCallback() {
        @Override
        public void callback(Object... data) throws RemoteException {

        }
    };