Flutter與Native通訊示例及源碼分析

前言

參考資料java

將Flutter添加到現有Android項目-官網android

撰寫雙端平臺代碼(插件編寫實現)git

Flutter 混合棧複用原理github

Flutter啓動頁(閃屏頁)具體實現和原理分析
數組

Android混合開發跳轉Flutter黑屏問題解決方法
bash

目錄



1、建立Flutter Module並進行相關配置

Android項目中建立Flutter Module 與其通訊交互網絡

一、建立Flutter Module,筆者將所建立的flutter_module放在跟AS建立的APP項目同一目錄層級上。app

flutter create -t module flutter_module
//或者
// Android Studio new Flutter Project -> flutter module複製代碼

二、配置 官網配置async

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')複製代碼

二、Java中調用Flutter 進入Flutter相關頁面ide

官網介紹 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便可。

2、Flutter與Native通訊示例

Flutter中定義了三種不一樣類型的Channel

  • BasicMessageChannel : 用於傳遞字符串和半結構的信息,持續通訊,收到消息後能夠回覆此消息。如Native將遍歷到的文件信息陸續傳遞到Dart,Flutter將從服務端陸續獲取的信息給Native。

    Flutter與原生項目的資源是不共享的,能夠經過BasicMessageChannel來獲取Native項目的圖標等資源

  • MethodChannel : 用於傳遞方法調用, 一次性通訊 ,好比Flutter調用Native獲取系統電量,發起Toast調用。

  • EventChannel : 用於數據流(event streams)的通訊,持續通訊,收到消息後沒法回覆這次消息,一般用於Native向Dart的通訊,如:手機電量變化、網絡鏈接變化、傳感器等。

一、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),
      ),
    );
  }
}
​複製代碼

二、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);
    });
  }複製代碼

三、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;
    }
  }複製代碼

3、Flutter與Native通訊源碼分析

幾個Channel方法的使用都很簡單,這裏主要介紹一下MethodChannel

在以前分析的MethodChannel中,能夠看出,只要兩端註冊同一個name的Channel就可讓Flutter端經過invokeMethod調用,返回一個Future對象,用於接收Native端返回的信息,Native層是經過onMethodCall中的Result類來處理相關事件的。

一、咱們先分析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);
     //.......
    }
  }複製代碼

二、咱們再來看看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處理消息。

三、總結

在Native端,先註冊名爲channelName的MethodChannel,並設置處理消息的MethodCallHandler,在Flutter端,一樣,構建一個名爲channelName的MethodChannel,而後調用相關方法時,會攜帶參數,經過dart native方法到jni層,而後到Native端,獲取指定的channelName,調用其onMessageChannel方法。其它兩種通訊也是相似。

4、數組的全排列

思路一:

全排列有 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);
            
        }
    }複製代碼


筆記五

相關文章
相關標籤/搜索