参考资料java
将Flutter添加到现有Android项目-官网android
Flutter 混合栈复用原理github
Android混合开发跳转Flutter黑屏问题解决方法
bash
Android项目中建立Flutter Module 与其通讯交互markdown
一、建立Flutter Module,笔者将所建立的flutter_module放在跟AS建立的APP项目同一目录层级上。网络
flutter create -t module flutter_module
//或者
// Android Studio new Flutter Project -> flutter module复制代码
二、配置 官网配置app
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相关页面async
官网介绍 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(); } } 复制代码
当你试事后,会发现两个问题
Native APP跳转Flutter出现先黑屏再显示问题 , 解决方案能够查看 Android混合开发跳转Flutter黑屏问题解决方法 Flutter启动页(闪屏页)具体实现和原理分析 我的解决方法是在原生Activity里面添加一个FlutterFragment就行了,没有出现黑屏,能够看接下来的示例代码
这样写,每次都重启了新的一摸同样的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中定义了三种不一样类型的Channel
BasicMessageChannel : 用于传递字符串和半结构的信息,持续通讯,收到消息后能够回复此消息。如Native将遍历到的文件信息陆续传递到Dart,Flutter将从服务端陆续获取的信息给Native。
Flutter与原生项目的资源是不共享的,能够经过BasicMessageChannel来获取Native项目的图标等资源
MethodChannel : 用于传递方法调用, 一次性通讯 ,好比Flutter调用Native获取系统电量,发起Toast调用。
EventChannel : 用于数据流(event streams)的通讯,持续通讯,收到消息后没法回复这次消息,一般用于Native向Dart的通讯,如:手机电量变化、网络链接变化、传感器等。
简单效果
代码
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), ), ); } } 复制代码
简单效果
代码
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); }); }复制代码
简单效果
代码
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; } }复制代码
几个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处,
注释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方法。其它两种通讯也是相似。
思路一:
全排列有 A(n,n) 种
给定一个n个元素组,其全排列过程能够理解为
任意取一个元素方法第一个位置,有n种方法
再从剩下的n-1个元素种选择一个放到第二个位置有 n -1 种,此时能够当作是对 n - 1个元素进行全排列
重复第二步,到最后一个元素
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); } } } }复制代码
可是上面的递归有两个问题,没有考虑到重复元素和栈空间,主要是栈空间不够的话,程序会崩溃。
重复元素能够在交换的时候判断当前元素和当前位置以后的元素是否还有相同的,没有则交互,而后递归。
思路二:
快速排序,对数组进行排序
每次从后寻找第一个data[i] < data[i+1]的下标pos,而后再从后向前(pos+1)找第一个data[i] > data[pos]的下标,交互位置,数组 pos + 1 到 length - 1反转颠倒 。作法意义是,每次固定最前面的数,不断交换排列后面的数(字典序最小状态)
反转意义 对于a[k+1,n-1],反转该区间内元素的顺序,即a[k+1]与a[n]交换,a[k+2]与a[n-1]交换,……,这样就获得了a[1…n]在字典序中的下一个排
例如 {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); } }复制代码
笔记五