Flutter与Native通信示例及源码分析

4,351 阅读10分钟

前言

参考资料

将Flutter添加到现有Android项目-官网

撰写双端平台代码(插件编写实现)

Flutter 混合栈复用原理

Flutter启动页(闪屏页)具体实现和原理分析

Android混合开发跳转Flutter黑屏问题解决方法

目录



一、创建Flutter Module并进行相关配置

Android项目中创建Flutter Module 与其通信交互

1、创建Flutter Module,笔者将所创建的flutter_module放在跟AS创建的APP项目同一目录层级上。

flutter create -t module flutter_module
//或者
// Android Studio new Flutter Project -> flutter module

2、配置 官网配置

1.android项目的settings.gradle,不用导包
setBinding(new Binding([gradle: this]))
evaluate(new File(settingsDir.parentFile, 'flutter_module/.android/include_flutter.groovy'))
2.同步后,再在android项目的app模块中即可
implementation project(':flutter')

3、Java中调用Flutter 进入Flutter相关页面

官网介绍 Flutter添加到现有Android项目 里面有关于如何添加FlutterActivity和FlutterFragment的

注意一些FlutterActivity需要注册到清单文件里

例如以下从native app 跳转到Flutter的主页面,并传递数据给Flutter,记得FlutterFragment的生命周期,按照官网写即可
    public void goToFlutterClick(View view) {
        startActivity(FlutterActivity.withNewEngine().initialRoute("Flutter Activity").build(this));
    }
​
    public void goToFlutterTarget(View view) {
        FlutterFragment flutterFragment = FlutterFragment.withNewEngine().initialRoute("Flutter Fragment").build();
        getSupportFragmentManager().beginTransaction().add(R.id.container, flutterFragment, "TAG").commit();
    }
}
   

当你试过后,会发现两个问题

  1. Native APP跳转Flutter出现先黑屏再显示问题 , 解决方案可以查看  Android混合开发跳转Flutter黑屏问题解决方法   Flutter启动页(闪屏页)具体实现和原理分析  个人解决方法是在原生Activity里面添加一个FlutterFragment就好了,没有出现黑屏,可以看接下来的示例代码

  2. 这样写,每次都重启了新的一摸一样的Flutter APP,解决方法就是通过再main.dart中,根据传递的参数来指定要显示的路由名,以确定要创建哪个窗口小部件给runApp

    void main() => run(_widgetForRoute(window.defaultRouteName))
    Widget _widgetForRoute(String route){
        switch(route){
            case 'route1':
                 return Widget1();
            case 'route2':
                 return Widget2();
            default:
                 return Center(child:Text('Are You Ok ?'));
        }
    }

小技巧:执行flutter attach命令后,在flutter端更改的代码也可以使用热加载、热重启功能。调试的时候,在Androd Studio上找到Flutter Attach按钮,点击,然后启动APP即可。

二、Flutter与Native通信示例

Flutter中定义了三种不同类型的Channel

  • BasicMessageChannel : 用于传递字符串和半结构的信息,持续通信,收到消息后可以回复此消息。如Native将遍历到的文件信息陆续传递到Dart,Flutter将从服务端陆续获取的信息给Native。

    Flutter与原生项目的资源是不共享的,可以通过BasicMessageChannel来获取Native项目的图标等资源

  • MethodChannel : 用于传递方法调用, 一次性通信 ,比如Flutter调用Native获取系统电量,发起Toast调用。

  • EventChannel : 用于数据流(event streams)的通信,持续通信,收到消息后无法回复此次消息,通常用于Native向Dart的通信,如:手机电量变化、网络连接变化、传感器等。

1、BasicMessageChannel

简单效果


代码

Native端

//1
import io.flutter.embedding.android.FlutterFragment;
// import xxxxxxx
public class FlutterTestActivity extends AppCompatActivity implements IShowMessage, View.OnClickListener {
​
    private EditText mInput;
    private Button mSend;
 
    private BasicMessageChannelPlugin basicMessageChannelPlugin;
    private FlutterFragment mFlutterfragment;
    private EventChannelPlugin eventChannelPlugin;
​
    @Override
    protected void onCreate(@Nullable Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.test);
        mInput = findViewById(R.id.input);
        mSend = findViewById(R.id.send);
     
​
        mFlutterfragment = FlutterFragment.withNewEngine().initialRoute("Flutter Fragment").build();
        getSupportFragmentManager().beginTransaction().add(R.id.flutter_test_fragment, mFlutterfragment, "TAG").commit();
    }
​
    public void basicChannelClick(View view) {
        basicMessageChannelPlugin = BasicMessageChannelPlugin.registerWith(this,mFlutterfragment.getFlutterEngine().getDartExecutor().getBinaryMessenger());
    }
    public void methodChannelClick(View view) {
        MethodChannelPlugin.registerWith(this,mFlutterfragment.getFlutterEngine().getDartExecutor().getBinaryMessenger());
    }
​
    public void eventChannelClick(View view) {
        eventChannelPlugin = EventChannelPlugin.registerWith(mFlutterfragment.getFlutterEngine().getDartExecutor().getBinaryMessenger());
    }
​
    @Override
    public void onShowMessage(String message) {
        Toast.makeText(this, "I hava receive " + message, Toast.LENGTH_SHORT).show();
    }
​
    @Override
    public void onClick(View view) {
        if(view == mSend){
            if(!TextUtils.isEmpty(mInput.getText().toString().trim())){
            basicMessageChannelPlugin.send(mInput.getText().toString().trim());
               // eventChannelPlugin.send(mInput.getText().toString().trim());
​
            }
        }
    }
​
}
​//2
/**封装收发消息*/
public class BasicMessageChannelPlugin implements BasicMessageChannel.MessageHandler<String>, BasicMessageChannel.Reply<String> {
    private final Activity activity;
    private final BasicMessageChannel<String> messageChannel;
​
    /**
     * 提供给外部调用注册
     *
     * @param binaryMessenger
     * @return
     */
    public static BasicMessageChannelPlugin registerWith(Activity activity, BinaryMessenger binaryMessenger) {
        return new BasicMessageChannelPlugin(activity, binaryMessenger);
    }
​
    private BasicMessageChannelPlugin(Activity activity, BinaryMessenger binaryMessenger) {
        this.activity = activity;
        // name 作为通道唯一标识,Dart端也需要一样
        this.messageChannel = new BasicMessageChannel<>(binaryMessenger, "BasicMessageChannelPlugin", StringCodec.INSTANCE);
        //设置消息处理器,处理来自Dart的消息
        messageChannel.setMessageHandler(this);
    }
​
    /**
     * 接收到消息后的处理
     *
     * @param message
     * @param reply
     */
    @Override
    public void onMessage(@Nullable String message, @NonNull BasicMessageChannel.Reply<String> reply) {
        Log.i("Basic", "收到Dart Send -> " + message);
        //通过replay回复Dart
        reply.reply("Native回复 -> BasicMessageChannel 收到 " + message);
        if (activity instanceof IShowMessage) {
            //IShowMessage为Activity实现的接口,这里主要用来处理收到的消息
            ((IShowMessage) activity).onShowMessage(message);
        }
        Toast.makeText(activity, message, Toast.LENGTH_SHORT).show();
    }
​
    /**
     * 发送消息
     *
     * @param message  发送的消息内容
     * @param callback 发送消息后,Dart端的反馈
     */
    void send(String message, BasicMessageChannel.Reply<String> callback) {
        messageChannel.send(message, callback);
    }
​
    public void send(String message) {
        send(message, this::reply);
    }
​
    @Override
    public void reply(@Nullable String reply) {
        //用于Send中接收Dart的反馈
        if (activity instanceof IShowMessage) {
            //IShowMessage为Activity实现的接口,这里主要用来处理收到的消息
            ((IShowMessage) activity).onShowMessage(reply);
        }
    }
}
//3
test.xml
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:orientation="vertical">

    <Button
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:onClick="basicChannelClick"
        android:text="BasicMessageChannel"
        android:textAllCaps="false" />

    <Button
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:onClick="methodChannelClick"
        android:text="MethodChannel"
        android:textAllCaps="false" />

    <Button
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:onClick="eventChannelClick"
        android:text="EventChannel"
        android:textAllCaps="false" />

    <LinearLayout
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:orientation="horizontal">

        <EditText
            android:id="@+id/input"
            android:layout_width="0dp"
            android:layout_height="wrap_content"
            android:layout_weight="1" />

        <Button
            android:id="@+id/send"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:text="发送" />
    </LinearLayout>

    <TextView
        android:id="@+id/show"
        android:layout_width="match_parent"
        android:layout_height="wrap_content" />

    <FrameLayout
        android:id="@+id/flutter_test_fragment"
        android:layout_width="match_parent"
        android:layout_height="match_parent" />
</LinearLayout>

Dart端

//修改创建的默认文件
class _MyHomePageState extends State<MyHomePage> {
  static const BasicMessageChannel _basicMessageChannel = const BasicMessageChannel("BasicMessageChannelPlugin", StringCodec());
​
  String receiveMessage = "";
  @override
  void initState() {
    // TODO: implement initState
    super.initState();
    _basicMessageChannel.setMessageHandler((message) => Future<String>((){
      setState(() {
        receiveMessage = message;
      });
      //收到消息后通知Native端
      return "收到Native 的消息 : "+ message;
    }));
    //向Native发送消息不等待回复
    _basicMessageChannel.send("Flutter Init Ok !");
  }
  //向Native发送消息并接收回复
  _send(message) async{
    String response = await _basicMessageChannel.send(message);
    print('native reply '+ response);
  }
​
  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: Text(widget.title),
      ),
      body: Center(
      
        child: Column(
 
          mainAxisAlignment: MainAxisAlignment.center,
          children: <Widget>[
            Text(
              'You have pushed the button this many times:',
            ),
            Text(
              '$receiveMessage',
              style: Theme.of(context).textTheme.headline4,
            ),
          ],
        ),
      ),
      floatingActionButton: FloatingActionButton(
        //onPressed: _sendToDart,
        child: Icon(Icons.add),
      ),
    );
  }
}
​

2、MethodChannel

官网MethodChannel获取电量示例

简单效果



代码

Native端

Activity代码上面分析BasicMessageChannel已经贴出来的,注册一下即可
​
public class MethodChannelPlugin implements MethodChannel.MethodCallHandler {
​
    private final Activity activity;
​
    public static void registerWith(Activity activity, BinaryMessenger binaryMessenger) {
        MethodChannel channel = new MethodChannel(binaryMessenger, "MethodChannelPlugin");
        MethodChannelPlugin instance = new MethodChannelPlugin(activity);
        channel.setMethodCallHandler(instance);
    }
​
    private MethodChannelPlugin(Activity activity) {
        this.activity = activity;
    }
​
    @Override
    public void onMethodCall(@NonNull MethodCall call, @NonNull MethodChannel.Result result) {
        //处理来自Dart的方法调用
        switch (call.method) {
            case "show":
                Log.i("MethodChannel","show方法 "+call.arguments());
                showMessage(call.arguments());
                //将返回结果给Dart
                result.success("MethodChannelPlugin收到 " + call.arguments);
                break;
            default:
                result.notImplemented();
                break;
        }
    }
​
    private void showMessage(String arguments) {
        if (activity instanceof IShowMessage) {
            ((IShowMessage) activity).onShowMessage(arguments);
        }
​
    }
}
​

Dart端

以下代码添加到上面分析BasicChannel的_MyHomePageState 即可,类似一样写 
​
static const MethodChannel _methodChannel = MethodChannel("MethodChannelPlugin");
​
floatingActionButton: FloatingActionButton(
        onPressed: _sendToDart,
        child: Icon(Icons.add),
      ),
      
 _sendToDart() {
    _methodChannel?.invokeMethod("show", 'Dart问候')?.then((value) {
      setState(() {
        this.receiveMessage = value;
      });
    })?.catchError((e) {
      print(e);
    });
  }

3、EventChannel

简单效果



代码

Native端

public class EventChannelPlugin implements EventChannel.StreamHandler {
​
    private  EventChannel.EventSink eventSink   ;
​
    public static EventChannelPlugin registerWith(BinaryMessenger binaryMessenger) {
        EventChannelPlugin plugin = new EventChannelPlugin();
        new EventChannel(binaryMessenger, "EventChannelPlugin").setStreamHandler(plugin);
        return plugin;
    }
​
    public void send(Object params){
        if(eventSink == null){
            return;
        }
​
        eventSink.success(params);
​
    }
​
    /**
     * Native监听事件时回调
     * @param arguments 传递的参数
     * @param events  Native回调Dart时的回调函数
     */
    @Override
    public void onListen(Object arguments, EventChannel.EventSink events) {
        Log.i("EventChannel","onListen " +arguments);
        this.eventSink = events;
    }
​
    /**
     * Flutter取消监听时的回调
     * @param arguments
     */
    @Override
    public void onCancel(Object arguments) {
        eventSink = null;
    }
}

Dart端

以下代码添加到上面分析BasicChannel的_MyHomePageState 即可,类似一样写,记得注册的事件在页面销毁时需要取消监听
static const EventChannel _eventChannel = EventChannel("EventChannelPlugin");
​
floatingActionButton: FloatingActionButton(
        onPressed: _sendToDart,
        child: Icon(Icons.add),
      ),
      
 _sendToDart() {
    _streamSubscription = _eventChannel
        .receiveBroadcastStream("123")
        .listen(_onToDart, onError: _onToDartError);
  }
    _onToDart(message) {
    setState(() {
      this.receiveMessage = "EventChannel " + message;
    });
  }
​
  _onToDartError(error) {
    print(error);
  }
@override
  void dispose() {
    super.dispose();
    if (_streamSubscription != null) {
      _streamSubscription.cancel();
      _streamSubscription = null;
    }
  }

三、Flutter与Native通信源码分析

几个Channel方法的使用都很简单,这里主要介绍一下MethodChannel

在之前分析的MethodChannel中,可以看出,只要两端注册同一个name的Channel就可以让Flutter端通过invokeMethod调用,返回一个Future对象,用于接收Native端返回的信息,Native层是通过onMethodCall中的Result类来处理相关事件的。

1、我们先分析Native端 MethodChannel,主要是MethodChannel的构造函数和设置消息处理的setMethoCallHandler方法

1.构造函数
 public MethodChannel(BinaryMessenger messenger, String name) {
    this(messenger, name, StandardMethodCodec.INSTANCE);
  }
 
  public MethodChannel(BinaryMessenger messenger, String name, MethodCodec codec) {
    if (BuildConfig.DEBUG) {
      if (messenger == null) {
        Log.e(TAG, "Parameter messenger must not be null.");
      }
      if (name == null) {
        Log.e(TAG, "Parameter name must not be null.");
      }
      if (codec == null) {
        Log.e(TAG, "Parameter codec must not be null.");
      }
    }
    this.messenger = messenger;
    this.name = name;
    this.codec = codec;
  }
  
 2.setMethodCallHandler 中 会将name和handler传递给messenger
   @UiThread
  public void setMethodCallHandler(final @Nullable MethodCallHandler handler) {
    messenger.setMessageHandler(
        name, handler == null ? null : new IncomingMethodCallHandler(handler));
  }
  

从上面的setMethodCallHandler可以看出关键点在于messenger和IncomingMethodCallHandler

messenger 这里的messenger其实就是BinaryMessenger,FlutterView和DartExecutor 等都实现了该接口,好多地方都使用FlutterView,因为这里Flutter版本是1.7的,不能通过老版本FlutterView去创建一个FlutterFragment,除非你Activity集成FlutterActivity,默认的getFlutterView()方法会返回FlutterView。应该是这样的。

代码中通过mFlutterfragment.getFlutterEngine().getDartExecutor().getBinaryMessenger()得到BinaryMessenger,所以setMethodCallHandler调用的是这个BinaryMessenger的setMethodCallHandler方法,而这个BinaryMessenger其实就是DartExceutor的dartMessenger对象

继续跟踪DartExecutor的dartMessenger对象

  public DartExecutor(@NonNull FlutterJNI flutterJNI, @NonNull AssetManager assetManager) {
    this.flutterJNI = flutterJNI;
    this.assetManager = assetManager;
    this.dartMessenger = new DartMessenger(flutterJNI);
    dartMessenger.setMessageHandler("flutter/isolate", isolateChannelMessageHandler);
    this.binaryMessenger = new DefaultBinaryMessenger(dartMessenger);
  }

可以看到dartMessenger是在这里初始化的,这个构造函数的执行在FlutterEngine里和FlutterNativeView里,至于哪个方法里执行,以后再分析,可以理解为在启动FlutterFragment的时候会执行。

所以我们只需要看DartMessenger的setMessageHandler方法

  @Override
  public void setMessageHandler(
      @NonNull String channel, @Nullable BinaryMessenger.BinaryMessageHandler handler) {
    if (handler == null) {
      Log.v(TAG, "Removing handler for channel '" + channel + "'");
      messageHandlers.remove(channel);
    } else {
      Log.v(TAG, "Setting handler for channel '" + channel + "'");
      messageHandlers.put(channel, handler);
    }
  }

从上述代码可以看出, 将name作为key,IncomingMethodCallHandler作为value,存放到了HashMap类型的messageHandlers中,通过key就可以找出对应的Handerl,然后执行相关方法(onMessage方法)

IncomingMethodCallHandler

  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);
     //.......
    }
  }

2、我们再来看看Flutter端

主要代码如下

static const MethodChannel _methodChannel = MethodChannel("MethodChannelPlugin");
    _methodChannel?.invokeMethod("show", 'Dart问候')?.then((value) {
      setState(() {
        this.receiveMessage = value;
      });
    })?.catchError((e) {
      print(e);
    });

MethodChannel构造函数

  const MethodChannel(this.name, [this.codec = const StandardMethodCodec(), BinaryMessenger binaryMessenger ])
      : assert(name != null),
        assert(codec != null),
        _binaryMessenger = binaryMessenger;

invokeMethod方法

 @optionalTypeArgs
  Future<T> invokeMethod<T>(String method, [ dynamic arguments ]) {
    return _invokeMethod<T>(method, missingOk: false, arguments: arguments);
  }
  
    @optionalTypeArgs
  Future<T> _invokeMethod<T>(String method, { bool missingOk, dynamic arguments }) async {
    assert(method != null);
    final ByteData result = await binaryMessenger.send(
      name,
      codec.encodeMethodCall(MethodCall(method, arguments)),
    );
    if (result == null) {
      if (missingOk) {
        return null;
      }
      throw MissingPluginException('No implementation found for method $method on channel $name');
    }
    return codec.decodeEnvelope(result) as T;
  }

可以看到_invokeMethod方法内,主要把方法明和参数通过codec转换为二进制数据,通过BinaryMessages send出去。

这里的binaryMessenger没有设置,所以是默认的defaultBinaryMessenger,跟踪发现是_DefaultBinaryMessenger类型对象,它是继成BinaryMessenger的。继续看它的send方法

//1 
@override
  Future<ByteData> send(String channel, ByteData message) {
    final MessageHandler handler = _mockHandlers[channel];
    if (handler != null)
      //A
      return handler(message);
      //B
    return _sendPlatformMessage(channel, message);
  }
  
//2
    Future<ByteData> _sendPlatformMessage(String channel, ByteData message) {
    final Completer<ByteData> completer = Completer<ByteData>();
    ui.window.sendPlatformMessage(channel, message, (ByteData reply) {
      //....
    });
    return completer.future;
  }
  
  //3
    void sendPlatformMessage(String name,
                           ByteData data,
                           PlatformMessageResponseCallback callback) {
    final String error =
        _sendPlatformMessage(name, _zonedPlatformMessageResponseCallback(callback), data);
    if (error != null)
      throw Exception(error);
  }
  //4 window.dart
    String _sendPlatformMessage(String name,
                              PlatformMessageResponseCallback callback,
                              ByteData data) native 'Window_sendPlatformMessage';

上面注释A处,

mockHandlers是一个<String,
MessageHandler>的Map,可以在Flutter中mock住某个channelName,这样的话,发送这类消息就会走自己在Flutter写的handler。我们需要和Native通信,自然这里没有mock住。

注释B处,从方法名就可以看出,这里是和平台通信的相关逻辑,主要是调用了ui.window.sendPlatformMessage方法,可以看后面 3 和 4,会发现调用的都是FlutterEngine的库方法,然后会调用dart的native方法 Window_sendPlatformMessage()。

Flutter Engine部分逻辑

这块先总结以下,Dart的Native机制会事先注册一个对native方法的映射表,上面那个dart的native方法会通过JNI层找到对应的java native层方法,调用其方法回到java native层,回到java层。

Dart的Native机制是先注册一个对Native的方法映射表

void Window::RegisterNatives(tonic::DartLibraryNatives* natives) {
  natives->Register({
      {"Window_defaultRouteName", DefaultRouteName, 1, true},
      {"Window_scheduleFrame", ScheduleFrame, 1, true},
      {"Window_sendPlatformMessage", _SendPlatformMessage, 4, true},
      {"Window_respondToPlatformMessage", _RespondToPlatformMessage, 3, true},
      {"Window_render", Render, 2, true},
      {"Window_updateSemantics", UpdateSemantics, 2, true},
      {"Window_setIsolateDebugName", SetIsolateDebugName, 2, true},
  });
}

我们可以找到对应的方法是_SendPlatformMessage,这个方法会调到SendPlatformMessage

  Dart_Handle SendPlatformMessage(Dart_Handle window,
                                const std::string& name,
                                Dart_Handle callback,
                                const tonic::DartByteData& data) {
  // ...
  if (Dart_IsNull(data.dart_handle())) {
    dart_state->window()->client()->HandlePlatformMessage( // A
        fml::MakeRefCounted<PlatformMessage>(name, response));
  } else {
    const uint8_t* buffer = static_cast<const uint8_t*>(data.data());
​
    dart_state->window()->client()->HandlePlatformMessage( // A
        fml::MakeRefCounted<PlatformMessage>(
            name, std::vector<uint8_t>(buffer, buffer + data.length_in_bytes()),
            response));
  }
​
  return Dart_Null();
}

可以看 注释 A 处,最后都是会调到WindowClient的HandlePlatformMessage方法,WindowClient的具体实现是RuntimeController,然后RuntimeController会将方法交给RuntimeDelegate来实现,而RuntimeDelegate的具体实现则是Engine类,这个类中的方法实现如下

void Engine::HandlePlatformMessage(
    fml::RefPtr<blink::PlatformMessage> message) {
  if (message->channel() == kAssetChannel) {
    HandleAssetPlatformMessage(std::move(message));
  } else {
    delegate_.OnEngineHandlePlatformMessage(std::move(message));
  }
}

查看 HandleAssetPlatformMessage(std::move(message)); 方法

void PlatformViewAndroid::HandlePlatformMessage(
    fml::RefPtr<blink::PlatformMessage> message) {
  JNIEnv* env = fml::jni::AttachCurrentThread();
  fml::jni::ScopedJavaLocalRef<jobject> view = java_object_.get(env);
  // ...
  auto java_channel = fml::jni::StringToJavaString(env, message->channel()); 
  if (message->hasData()) {
    fml::jni::ScopedJavaLocalRef<jbyteArray> message_array(env, env->NewByteArray(message->data().size()));
    env->SetByteArrayRegion(
        message_array.obj(), 0, message->data().size(),
        reinterpret_cast<const jbyte*>(message->data().data()));
    message = nullptr;
​
    // This call can re-enter in InvokePlatformMessageXxxResponseCallback.
    FlutterViewHandlePlatformMessage(env, view.obj(), java_channel.obj(),
                                     message_array.obj(), response_id);   
  } else {
    message = nullptr;
​
    // This call can re-enter in InvokePlatformMessageXxxResponseCallback.
    FlutterViewHandlePlatformMessage(env, view.obj(), java_channel.obj(),
                                     nullptr, response_id);             
  }
}

上面这个方法最后调用了 FlutterViewHandlePlatformMessage()方法发起调用。这个方法指定了Java类和方法,调用了FlutterNativeView的handlePlatformMessage方法。

static jmethodID g_handle_platform_message_method = nullptr;
void FlutterViewHandlePlatformMessage(JNIEnv* env,
                                      jobject obj,
                                      jstring channel,
                                      jobject message,
                                      jint responseId) {
  env->CallVoidMethod(obj, g_handle_platform_message_method, channel, message,
                      responseId); // (1)
  FML_CHECK(CheckException(env));
}
// ...
bool PlatformViewAndroid::Register(JNIEnv* env) {
  // ...
  g_flutter_native_view_class = new fml::jni::ScopedJavaGlobalRef<jclass>(
      env, env->FindClass("io/flutter/view/FlutterNativeView")); // (2)
  // ...
  g_handle_platform_message_method =
    env->GetMethodID(g_flutter_native_view_class->obj(),
                     "handlePlatformMessage", "(Ljava/lang/String;[BI)V"); // (3)
  // ...
}

我们回到Native端继续看FlutterNativeView的handlePlatformMessage方法

private void handlePlatformMessage(
    @NonNull final String channel, byte[] message, final int replyId) {
  if (platformMessageHandler != null) {
    platformMessageHandler.handleMessageFromDart(channel, message, replyId);
  }
  // TODO(mattcarroll): log dropped messages when in debug mode
  // (https://github.com/flutter/flutter/issues/25391)
}

这个platformMessageHandler其实就是DartMessenger。

@Override
public void handleMessageFromDart(
    @NonNull final String channel, @Nullable byte[] message, final int replyId) {
  Log.v(TAG, "Received message from Dart over channel '" + channel + "'");
  BinaryMessenger.BinaryMessageHandler handler = messageHandlers.get(channel);
  if (handler != null) {
    try {
      Log.v(TAG, "Deferring to registered handler to process message.");
      final ByteBuffer buffer = (message == null ? null : ByteBuffer.wrap(message));
      handler.onMessage(buffer, new Reply(flutterJNI, replyId));
    } catch (Exception ex) {
      Log.e(TAG, "Uncaught exception in binary message listener", ex);
      flutterJNI.invokePlatformMessageEmptyResponseCallback(replyId);
    }
  } else {
    Log.v(TAG, "No registered handler for message. Responding to Dart with empty reply message.");
    flutterJNI.invokePlatformMessageEmptyResponseCallback(replyId);
  }
}

从这个方法可以看出messageHandlers和之前的Handler是同一个对象,取出对应的ChannelName后,调用对应的Handler的onMessage处理消息。

3、总结

在Native端,先注册名为channelName的MethodChannel,并设置处理消息的MethodCallHandler,在Flutter端,同样,构建一个名为channelName的MethodChannel,然后调用相关方法时,会携带参数,通过dart native方法到jni层,然后到Native端,获取指定的channelName,调用其onMessageChannel方法。其它两种通信也是类似。

四、数组的全排列

思路一:

全排列有 A(n,n) 种

给定一个n个元素组,其全排列过程可以理解为

  1. 任意取一个元素方法第一个位置,有n种方法

  2. 再从剩下的n-1个元素种选择一个放到第二个位置有 n -1 种,此时可以看成是对 n - 1个元素进行全排列

  3. 重复第二步,到最后一个元素

public class One {
    private void println(int[] data,int len) {
        System.out.print("{");
        for(int i = 0;i<len;i++) {
            System.out.print(data[i] + "");
        }
        System.out.println("}");
    }
    private void swap(int[] data,int i ,int j) {
        int temp = data[i];
        data[i] = data[j];
        data[j]= temp; 
    }
    public void permutation(int[] data,int len,int index) {
        if(index == len) {
            //全排列结束
            println(data, len);
        }else {
            for(int i = index;i < len;i++) {
                //将第i个元素交换到当前index处
                swap(data, index, i);
                //对剩下的元素进行全排列
                permutation(data, len, index+1);
                //将第i个元素交换回原位
                swap(data, index, i);
            }
        }
    }
}

但是上面的递归有两个问题,没有考虑到重复元素和栈空间,主要是栈空间不够的话,程序会崩溃。

重复元素可以在交换的时候判断当前元素和当前位置之后的元素是否还有相同的,没有则交互,然后递归。

思路二:

  1. 快速排序,对数组进行排序

  2. 每次从后寻找第一个data[i] < data[i+1]的下标pos,然后再从后向前(pos+1)找第一个data[i] > data[pos]的下标,交互位置,数组 pos + 1 到 length - 1反转颠倒 。做法意义是,每次固定最前面的数,不断交换排列后面的数(字典序最小状态)

  3. 反转意义 对于a[k+1,n-1],反转该区间内元素的顺序,即a[k+1]与a[n]交换,a[k+2]与a[n-1]交换,……,这样就得到了a[1…n]在字典序中的下一个排

  4. 例如 {1,2,3,4} ==>>

    {1234}

    {1243} {1324} {1342} {1423} {1432} .......

    private void reverse(int[] data,int s,int e) {
        while(s < e) {
            swap(data, s, e);
            s++;
            e--;
        }
    }
​
    public void permutation(int[] data, int len, int index) {
        if (data == null) {
            return;
        }
        //1.排序
        Arrays.sort(data);
        println(data, len);
        while(true) {
            int pos = -1;
            //从后往前找第一个替换点
            for(int i = len -2;i>=0;i--) {
                if(data[i]< data[i+1] ) {
                    pos = i;
                    break;
                }
            }
                if(pos == -1) {
                    break;
                }
                //从后往前寻找第一个大于替换点的元素
                int sencondIndex = -1;
                for(int i= len -1;i> pos;i--) {
                    if(data[i]> data[pos] ) {
                        sencondIndex = i;
                        break;
                    }
                }
                //交换
                swap(data, pos, sencondIndex);
                //颠倒
                reverse(data, pos+1, len-1);
                println(data, len);
            
        }
    }


笔记五