安卓 Flutter Channel 源码解析

Flutter 官方提供三种 Platform Dart 端消息通信方式,他们分别是 MethodChannel BasicMessageChannel EventChannel
MethodChanel :用于传递方法调用, MethodCallHandler 最终必须在 UI 线程通过 result.
success(x) 方法返回结果,返回前自己可以异步新起线程做任意耗时操作。
BasicMessageChannel :用于传递字符串和半结构化的消息。
EventChannel :用于数据流的发送。
Android Platform Channel 定义
public class MethodChannel {
  private final BinaryMessenger messenger;
  private final String name;
  private final MethodCodec codec;
  //......
  private final class IncomingMethodCallHandler implements BinaryMessageHandler {
    private final MethodCallHandler handler;
  }
}

public final class BasicMessageChannel<T> {
  @NonNull private final BinaryMessenger messenger;
  @NonNull private final String name;
  @NonNull private final MessageCodec<T> codec;
  //......
  private final class IncomingMessageHandler implements BinaryMessageHandler {
    private final MessageHandler<T> handler;
  }
}

public final class EventChannel {
  private final BinaryMessenger messenger;
  private final String name;
  private final MethodCodec codec;
  //......
  private final class IncomingStreamRequestHandler implements BinaryMessageHandler {
    private final StreamHandler handler;
  }
}

  MethodChannelBasicMessageChannelEventChannel 结构来看,都是由namemessengercodec三个属性字段组成

name:String 类型,唯一标识符代表 Channel 的名字,因为一个 Flutter 应用中存在多个                         Channel,每个 Channel 在创建时必须指定一个独一无二的 name 作为标识
messenger:BinaryMessenger 类型,充当信使邮递员角色,消息的发送与接收工具人。
codec:MethodCodec 或MessageCodec<T>类型,充当消息的编解码器。

重点逻辑是messenger字段,看下BinaryMessenger定义

public interface BinaryMessenger {

   public interface TaskQueue {}

  @UiThread
  void send(@NonNull String channel, @Nullable ByteBuffer message, @Nullable BinaryReply callback);


  @UiThread
  void setMessageHandler(@NonNull String channel, @Nullable BinaryMessageHandler handler);

  interface BinaryMessageHandler {
  
    @UiThread
    void onMessage(@Nullable ByteBuffer message, @NonNull BinaryReply reply);
  }

   */
  interface BinaryReply {
   
    void reply(@Nullable ByteBuffer reply);
  }

}
看下DartMessenger实现类
class DartMessenger implements BinaryMessenger, PlatformMessageHandler {

  @NonNull private final Map<String, HandlerInfo> messageHandlers = new HashMap<>();
  
@Override
  public void setMessageHandler(
      @NonNull String channel,
      @Nullable BinaryMessenger.BinaryMessageHandler handler,
      @Nullable TaskQueue taskQueue) {
    ......

    List<BufferedMessageInfo> list;
    synchronized (handlersLock) {
      messageHandlers.put(channel, new HandlerInfo(handler, dartMessengerTaskQueue));
    ......
    }
    ......
    }
  }

  @Override
  public void handleMessageFromDart(
      @NonNull String channel, @Nullable ByteBuffer message, int replyId, long messageData) {

    synchronized (handlersLock) {
      handlerInfo = messageHandlers.get(channel);
      messageDeferred = (enableBufferingIncomingMessages.get() && handlerInfo == null);
     ......
    if (!messageDeferred) {
      dispatchMessageToQueue(channel, handlerInfo, message, replyId, messageData);
    }
  }

  private void dispatchMessageToQueue(
      @NonNull String channel,
      @Nullable HandlerInfo handlerInfo,
      @Nullable ByteBuffer message,
      int replyId,
      long messageData) {
    // Called from any thread.
    final DartMessengerTaskQueue taskQueue = (handlerInfo != null) ? handlerInfo.taskQueue : null;
    TraceSection.beginAsyncSection("PlatformChannel ScheduleHandler on " + channel, replyId);
    Runnable myRunnable =
        () -> {
          TraceSection.endAsyncSection("PlatformChannel ScheduleHandler on " + channel, replyId);
          try (TraceSection e =
              TraceSection.scoped("DartMessenger#handleMessageFromDart on " + channel)) {
            invokeHandler(handlerInfo, message, replyId);
            if (message != null && message.isDirect()) {
              // This ensures that if a user retains an instance to the ByteBuffer and it
              // happens to be direct they will get a deterministic error.
              message.limit(0);
            }
          } finally {
            // This is deleting the data underneath the message object.
            flutterJNI.cleanupMessageData(messageData);
          }
        };
    final DartMessengerTaskQueue nonnullTaskQueue =
        taskQueue == null ? platformTaskQueue : taskQueue;
    nonnullTaskQueue.dispatch(myRunnable);
  }


  private void invokeHandler(
      @Nullable HandlerInfo handlerInfo, @Nullable ByteBuffer message, final int replyId) {
    // Called from any thread.
    if (handlerInfo != null) {
      try {
        Log.v(TAG, "Deferring to registered handler to process message.");
        handlerInfo.handler.onMessage(message, new Reply(flutterJNI, replyId));
      } catch (Exception ex) {
        Log.e(TAG, "Uncaught exception in binary message listener", ex);
        flutterJNI.invokePlatformMessageEmptyResponseCallback(replyId);
      } catch (Error err) {
        handleError(err);
      }
    } else {
      Log.v(TAG, "No registered handler for message. Responding to Dart with empty reply message.");
      flutterJNI.invokePlatformMessageEmptyResponseCallback(replyId);
    }
  }
}

 上面整体流程先注册handler,以channel name为key缓存到messageHandlers,等待

handleMessageFromDart(String channel, ByteBuffer message, int replyId, long messageData)
从Flutter端收到数据后,根据channel参数从messageHandlers获取到对应HandlerInfo对象,然后执行该队向的onMessage方法 handlerInfo.handler.onMessage(message, new Reply(flutterJNI, replyId));

这里可以先看下Reply对象,创建Reply对象保存replyId字段,后面用来回复Flutter。

  static class Reply implements BinaryMessenger.BinaryReply {
    @NonNull private final FlutterJNI flutterJNI;
    private final int replyId;
    private final AtomicBoolean done = new AtomicBoolean(false);

    Reply(@NonNull FlutterJNI flutterJNI, int replyId) {
      this.flutterJNI = flutterJNI;
      this.replyId = replyId;
    }

    @Override
    public void reply(@Nullable ByteBuffer reply) {
      if (done.getAndSet(true)) {
        throw new IllegalStateException("Reply already submitted");
      }
      if (reply == null) {
        flutterJNI.invokePlatformMessageEmptyResponseCallback(replyId);
      } else {
        flutterJNI.invokePlatformMessageResponseCallback(replyId, reply, reply.position());
      }
    }
  }

通过flutterJNI调用invokePlatformMessageResponseCallback发送到Flutter端

现在回过头继续跟踪setMessageHandler流程,前面提到channel有MethodChannelEventChannelBasicMessageChannel,分别看下它们是如何注册handler的,三种类型有啥不一样。

先看MethodChannel类型

public class MethodChannel {
  private static final String TAG = "MethodChannel#";

  private final BinaryMessenger messenger;
  private final String name;
  private final MethodCodec codec;
  private final BinaryMessenger.TaskQueue taskQueue;

 ......

  @UiThread
  public void setMethodCallHandler(final @Nullable MethodCallHandler handler) {
    // We call the 2 parameter variant specifically to avoid breaking changes in
    // mock verify calls.
    // See https://github.com/flutter/flutter/issues/92582.
    if (taskQueue != null) {
      messenger.setMessageHandler(
          name, handler == null ? null : new IncomingMethodCallHandler(handler), taskQueue);
    } else {
      messenger.setMessageHandler(
          name, handler == null ? null : new IncomingMethodCallHandler(handler));
    }
  }
......
}

注册的类型为IncomingMethodCallHandler,从Incoming名字看就是“接听”,用来处理Flutter端发送的数据。

  private final class IncomingMethodCallHandler implements BinaryMessageHandler {
    private final MethodCallHandler handler;

    IncomingMethodCallHandler(MethodCallHandler handler) {
      this.handler = handler;
    }

    @Override
    @UiThread
    public void onMessage(ByteBuffer message, final BinaryReply reply) {
      final MethodCall call = codec.decodeMethodCall(message);
      try {
        handler.onMethodCall(
            call,
            new Result() {
              @Override
              public void success(Object result) {
                reply.reply(codec.encodeSuccessEnvelope(result));
              }

              @Override
              public void error(String errorCode, String errorMessage, Object errorDetails) {
                reply.reply(codec.encodeErrorEnvelope(errorCode, errorMessage, errorDetails));
              }

              @Override
              public void notImplemented() {
                reply.reply(null);
              }
            });
      } catch (RuntimeException e) {
        Log.e(TAG + name, "Failed to handle method call", e);
        reply.reply(
            codec.encodeErrorEnvelopeWithStacktrace(
                "error", e.getMessage(), null, Log.getStackTraceString(e)));
      }
    }
  }

onMessage方法通过codec编码器将字节数组message转化成MethodCall对象,MethodCall对象里面包括方法名称和方法携带参数

再看EventChannel类型

public final class EventChannel {
  private static final String TAG = "EventChannel#";

  private final BinaryMessenger messenger;
  private final String name;
  private final MethodCodec codec;
  @Nullable private final BinaryMessenger.TaskQueue taskQueue;

  ......
  public void setStreamHandler(final StreamHandler handler) {
    // We call the 2 parameter variant specifically to avoid breaking changes in
    // mock verify calls.
    // See https://github.com/flutter/flutter/issues/92582.
    if (taskQueue != null) {
      messenger.setMessageHandler(
          name, handler == null ? null : new IncomingStreamRequestHandler(handler), taskQueue);
    } else {
      messenger.setMessageHandler(
          name, handler == null ? null : new IncomingStreamRequestHandler(handler));
    }
  }
......
}

注册的类型为IncomingStreamRequestHandler,从Incoming名字看也是带“接听”,同样是用来处理Flutter端发送的数据。

 private final class IncomingStreamRequestHandler implements BinaryMessageHandler {
    private final StreamHandler handler;
    private final AtomicReference<EventSink> activeSink = new AtomicReference<>(null);

    IncomingStreamRequestHandler(StreamHandler handler) {
      this.handler = handler;
    }

    @Override
    public void onMessage(ByteBuffer message, final BinaryReply reply) {
      final MethodCall call = codec.decodeMethodCall(message);
      if (call.method.equals("listen")) {
        onListen(call.arguments, reply);
      } else if (call.method.equals("cancel")) {
        onCancel(call.arguments, reply);
      } else {
        reply.reply(null);
      }
    }
}

IncomingStreamRequestHandler 的onMessage方法通过使用codec编码器将字节数组转成MethodCall对象,可以看到该对象只有listencancel两个方法,listen标识监听,cancel标识取消监听

最后再看BasicMessageChannel

public final class BasicMessageChannel<T> {
  private static final String TAG = "BasicMessageChannel#";
  public static final String CHANNEL_BUFFERS_CHANNEL = "dev.flutter/channel-buffers";

  @NonNull private final BinaryMessenger messenger;
  @NonNull private final String name;
  @NonNull private final MessageCodec<T> codec;
  @Nullable private final BinaryMessenger.TaskQueue taskQueue;

......
  public void setMessageHandler(@Nullable final MessageHandler<T> handler) {
    // We call the 2 parameter variant specifically to avoid breaking changes in
    // mock verify calls.
    // See https://github.com/flutter/flutter/issues/92582.
    if (taskQueue != null) {
      messenger.setMessageHandler(
          name, handler == null ? null : new IncomingMessageHandler(handler), taskQueue);
    } else {
      messenger.setMessageHandler(
          name, handler == null ? null : new IncomingMessageHandler(handler));
    }
  }

......
}

注册的类型为IncomingMessageHandler,名字依然带Incoming,同样是用来处理Flutter端发送的数据。

  private final class IncomingMessageHandler implements BinaryMessageHandler {
    private final MessageHandler<T> handler;

    private IncomingMessageHandler(@NonNull MessageHandler<T> handler) {
      this.handler = handler;
    }

    @Override
    public void onMessage(@Nullable ByteBuffer message, @NonNull final BinaryReply callback) {
      try {
        handler.onMessage(
            codec.decodeMessage(message),
            new Reply<T>() {
              @Override
              public void reply(T reply) {
                callback.reply(codec.encodeMessage(reply));
              }
            });
      } catch (RuntimeException e) {
        Log.e(TAG + name, "Failed to handle message", e);
        callback.reply(null);
      }
    }
  }

onMessage方法里面将message通过codec编码器转成T对应类型。

通过上面的代码跟踪,我们已经明了MethodChannel注册到messageHandlers里面的是IncomingMethodCallHandler,EventChannel注册的是IncomingStreamRequestHandler,BasicMessageChannel注册的是IncomingMessageHandler

MethodChannelIncomingMethodCallHandler
EventChannelIncomingStreamRequestHandler
BasicMessageChannelIncomingMessageHandler

我们继续跟踪IncomingMethodCallHandler,确认它是如何处理Flutter的方法调用

我们以官方的MouseCursorChannel为例,确认逻辑细节

public class MouseCursorChannel {
  private static final String TAG = "MouseCursorChannel";

  @NonNull public final MethodChannel channel;
  @Nullable private MouseCursorMethodHandler mouseCursorMethodHandler;

  public MouseCursorChannel(@NonNull DartExecutor dartExecutor) {
    channel = new MethodChannel(dartExecutor, "flutter/mousecursor", StandardMethodCodec.INSTANCE);
    channel.setMethodCallHandler(parsingMethodCallHandler);
  }

  /**
   * Sets the {@link MouseCursorMethodHandler} which receives all events and requests that are
   * parsed from the underlying platform channel.
   */
  public void setMethodHandler(@Nullable MouseCursorMethodHandler mouseCursorMethodHandler) {
    this.mouseCursorMethodHandler = mouseCursorMethodHandler;
  }

  @NonNull
  private final MethodChannel.MethodCallHandler parsingMethodCallHandler =
      new MethodChannel.MethodCallHandler() {
        @Override
        public void onMethodCall(@NonNull MethodCall call, @NonNull MethodChannel.Result result) {
          if (mouseCursorMethodHandler == null) {
            // If no explicit mouseCursorMethodHandler has been registered then we don't
            // need to forward this call to an API. Return.
            return;
          }

          final String method = call.method;
          Log.v(TAG, "Received '" + method + "' message.");
          try {
            // More methods are expected to be added here, hence the switch.
            switch (method) {
              case "activateSystemCursor":
                @SuppressWarnings("unchecked")
                final HashMap<String, Object> data = (HashMap<String, Object>) call.arguments;
                final String kind = (String) data.get("kind");
                try {
                  mouseCursorMethodHandler.activateSystemCursor(kind);
                } catch (Exception e) {
                  result.error("error", "Error when setting cursors: " + e.getMessage(), null);
                  break;
                }
                result.success(true);
                break;
              default:
            }
          } catch (Exception e) {
            result.error("error", "Unhandled error: " + e.getMessage(), null);
          }
        }
      };

  @VisibleForTesting
  public void synthesizeMethodCall(@NonNull MethodCall call, @NonNull MethodChannel.Result result) {
    parsingMethodCallHandler.onMethodCall(call, result);
  }

  public interface MouseCursorMethodHandler {
    // Called when the pointer should start displaying a system mouse cursor
    // specified by {@code shapeCode}.
    public void activateSystemCursor(@NonNull String kind);
  }
}

可以看到,真正干活的handler就是parsingMethodCallHandler,它里面复写了onMethodCall方法,从源码可以看出支持方法名activateSystemCursor,执行完成后通过result.success(true)回调回去,这里的result就是前面的Result


    public void onMessage(ByteBuffer message, final BinaryReply reply) {
      final MethodCall call = codec.decodeMethodCall(message);
      try {
        handler.onMethodCall(
            call,
            new Result() {
              @Override
              public void success(Object result) {
                reply.reply(codec.encodeSuccessEnvelope(result));
              }

              @Override
              public void error(String errorCode, String errorMessage, Object errorDetails) {
                reply.reply(codec.encodeErrorEnvelope(errorCode, errorMessage, errorDetails));
              }

              @Override
              public void notImplemented() {
                reply.reply(null);
              }
            });
      } catch (RuntimeException e) {
        Log.e(TAG + name, "Failed to handle method call", e);
        reply.reply(
            codec.encodeErrorEnvelopeWithStacktrace(
                "error", e.getMessage(), null, Log.getStackTraceString(e)));
      }
    }

result接收到success回调后,通过reply.reply 回调给Flutter层。

这样就明确了,Android从Flutter端收到数据后,执行完对应方法后,再通过reply通过FlutterJNI发送到Flutter,这样一个调用回路就形成了。

EventChannel和BasicMessageChannel逻辑也是类似,这里就不再赘述,大家可以查阅源码进行分析。

上面的整个流程都是Flutter调用Android原生的方法流程,接下来我们跟踪下Android如何Flutter的方法

我们以NavigationChannel为例,看看它是如何调用的

  public void pushRoute(@NonNull String route) {
    Log.v(TAG, "Sending message to push route '" + route + "'");
    channel.invokeMethod("pushRoute", route);
  }
  @UiThread
  public void invokeMethod(@NonNull String method, @Nullable Object arguments) {
    invokeMethod(method, arguments, null);
  }
  @UiThread
  public void invokeMethod(
      @NonNull String method, @Nullable Object arguments, @Nullable Result callback) {
    messenger.send(
        name,
        codec.encodeMethodCall(new MethodCall(method, arguments)),
        callback == null ? null : new IncomingResultHandler(callback));
  }
  @Override
  public void send(
      @NonNull String channel,
      @Nullable ByteBuffer message,
      @Nullable BinaryMessenger.BinaryReply callback) {
    try (TraceSection e = TraceSection.scoped("DartMessenger#send on " + channel)) {
      Log.v(TAG, "Sending message with callback over channel '" + channel + "'");
      int replyId = nextReplyId++;
      if (callback != null) {
        pendingReplies.put(replyId, callback);
      }
      if (message == null) {
        flutterJNI.dispatchEmptyPlatformMessage(channel, replyId);
      } else {
        flutterJNI.dispatchPlatformMessage(channel, message, message.position(), replyId);
      }
    }
  }

跟踪源码,我们看到最后是通过flutterJNI调用了dispatchPlatformMessage方法发送到了Flutter层。

Android原生MethodChannel整体调用流程如下图

接下来我们根据下MethodChannel里面的codec编码器是如何工作的。

我们可以看到MethodChannel里面的codec是MethodCodec类型。

public interface MethodCodec {

  @NonNull
  ByteBuffer encodeMethodCall(@NonNull MethodCall methodCall);


  @NonNull
  MethodCall decodeMethodCall(@NonNull ByteBuffer methodCall);


  @NonNull
  ByteBuffer encodeSuccessEnvelope(@Nullable Object result);


  @NonNull
  ByteBuffer encodeErrorEnvelope(
      @NonNull String errorCode, @Nullable String errorMessage, @Nullable Object errorDetails);


  @NonNull
  ByteBuffer encodeErrorEnvelopeWithStacktrace(
      @NonNull String errorCode,
      @Nullable String errorMessage,
      @Nullable Object errorDetails,
      @Nullable String errorStacktrace);
  @NonNull
  Object decodeEnvelope(@NonNull ByteBuffer envelope);
}

这里一般使用的是StandardMethodCodec类型。

public final class StandardMethodCodec implements MethodCodec {
  public static final StandardMethodCodec INSTANCE =
      new StandardMethodCodec(StandardMessageCodec.INSTANCE);
  private final StandardMessageCodec messageCodec;

  /** Creates a new method codec based on the specified message codec. */
  public StandardMethodCodec(@NonNull StandardMessageCodec messageCodec) {
    this.messageCodec = messageCodec;
  }

  @Override
  @NonNull
  public ByteBuffer encodeMethodCall(@NonNull MethodCall methodCall) {
    final ExposedByteArrayOutputStream stream = new ExposedByteArrayOutputStream();
    messageCodec.writeValue(stream, methodCall.method);
    messageCodec.writeValue(stream, methodCall.arguments);
    final ByteBuffer buffer = ByteBuffer.allocateDirect(stream.size());
    buffer.put(stream.buffer(), 0, stream.size());
    return buffer;
  }

  @Override
  @NonNull
  public MethodCall decodeMethodCall(@NonNull ByteBuffer methodCall) {
    methodCall.order(ByteOrder.nativeOrder());
    final Object method = messageCodec.readValue(methodCall);
    final Object arguments = messageCodec.readValue(methodCall);
    if (method instanceof String && !methodCall.hasRemaining()) {
      return new MethodCall((String) method, arguments);
    }
    throw new IllegalArgumentException("Method call corrupted");
  }
}

可以看到encodeMethodCall将MethodCall对象编码成字节数组,decodeMethodCall将字节数组转化成MethodCall对象。这里的核心算法是通过messageCodec writeValue和readValue转化。

  protected void writeValue(@NonNull ByteArrayOutputStream stream, @Nullable Object value) {
    if (value == null || value.equals(null)) {
      stream.write(NULL);
    } else if (value instanceof Boolean) {
      stream.write(((Boolean) value).booleanValue() ? TRUE : FALSE);
    } else if (value instanceof Number) {
      if (value instanceof Integer || value instanceof Short || value instanceof Byte) {
        stream.write(INT);
        writeInt(stream, ((Number) value).intValue());
      } else if (value instanceof Long) {
        stream.write(LONG);
        writeLong(stream, (long) value);
      } else if (value instanceof Float || value instanceof Double) {
        stream.write(DOUBLE);
        writeAlignment(stream, 8);
        writeDouble(stream, ((Number) value).doubleValue());
      } else if (value instanceof BigInteger) {
        stream.write(BIGINT);
        writeBytes(stream, ((BigInteger) value).toString(16).getBytes(UTF8));
      } else {
        throw new IllegalArgumentException("Unsupported Number type: " + value.getClass());
      }
    } else if (value instanceof CharSequence) {
      stream.write(STRING);
      writeBytes(stream, value.toString().getBytes(UTF8));
    } else if (value instanceof byte[]) {
      stream.write(BYTE_ARRAY);
      writeBytes(stream, (byte[]) value);
    } else if (value instanceof int[]) {
      stream.write(INT_ARRAY);
      final int[] array = (int[]) value;
      writeSize(stream, array.length);
      writeAlignment(stream, 4);
      for (final int n : array) {
        writeInt(stream, n);
      }
    } else if (value instanceof long[]) {
      stream.write(LONG_ARRAY);
      final long[] array = (long[]) value;
      writeSize(stream, array.length);
      writeAlignment(stream, 8);
      for (final long n : array) {
        writeLong(stream, n);
      }
    } else if (value instanceof double[]) {
      stream.write(DOUBLE_ARRAY);
      final double[] array = (double[]) value;
      writeSize(stream, array.length);
      writeAlignment(stream, 8);
      for (final double d : array) {
        writeDouble(stream, d);
      }
    } else if (value instanceof List) {
      stream.write(LIST);
      final List<?> list = (List) value;
      writeSize(stream, list.size());
      for (final Object o : list) {
        writeValue(stream, o);
      }
    } else if (value instanceof Map) {
      stream.write(MAP);
      final Map<?, ?> map = (Map) value;
      writeSize(stream, map.size());
      for (final Entry<?, ?> entry : map.entrySet()) {
        writeValue(stream, entry.getKey());
        writeValue(stream, entry.getValue());
      }
    } else if (value instanceof float[]) {
      stream.write(FLOAT_ARRAY);
      final float[] array = (float[]) value;
      writeSize(stream, array.length);
      writeAlignment(stream, 4);
      for (final float f : array) {
        writeFloat(stream, f);
      }
    } else {
      throw new IllegalArgumentException(
          "Unsupported value: '" + value + "' of type '" + value.getClass() + "'");
    }
  }

可以看到写入到字节流时,先写入类型,再写入数据,类型固定占一个字节。

  private static final byte NULL = 0;
  private static final byte TRUE = 1;
  private static final byte FALSE = 2;
  private static final byte INT = 3;
  private static final byte LONG = 4;
  private static final byte BIGINT = 5;
  private static final byte DOUBLE = 6;
  private static final byte STRING = 7;
  private static final byte BYTE_ARRAY = 8;
  private static final byte INT_ARRAY = 9;
  private static final byte LONG_ARRAY = 10;
  private static final byte DOUBLE_ARRAY = 11;
  private static final byte LIST = 12;
  private static final byte MAP = 13;
  private static final byte FLOAT_ARRAY = 14;

我们追踪下字符串如何写入

if (value instanceof CharSequence) {
      stream.write(STRING);
      writeBytes(stream, value.toString().getBytes(UTF8));
    } 

-------------------------------------------------------------------------

  protected static final void writeBytes(
      @NonNull ByteArrayOutputStream stream, @NonNull byte[] bytes) {
    writeSize(stream, bytes.length);
    stream.write(bytes, 0, bytes.length);
  }

先写入STRING类型,再写入字符串的长度,再写入字符串内容。

现在我们已经明确了,通过类型+(数据长度)+数据就能将方法进行编码,响应的我们根据这个规则就可以将字节数据进行解码,获得方法名和参数类型。

类型数据长度数据......

从上面也能看到,这里不支持自定义类型,只支持普通数据类型。

  • 25
    点赞
  • 13
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值