Native
和Flutter
混合开发,通过FlutterFragment
加载Flutter
页面,但Flutter
页面第一次加载时非常缓慢,可以通过Flutter
预加载的方式来减少第一次加载的耗时。
预备知识:
Native
进程只有一个DartVM
FlutterEngine
初始化时,会创建并初始化DartVM
DartVM
可以有多个FlutterEngine
,每个FlutterEngine
都运行在自己的Isolate
中,他们的内存数据不共享,需要通过Isolate事先设置的port(顶级函数)通讯。实现方式:Flutter
页面第一次调用时,会初始化Flutter
相关的东西,比如FlutterEngine
,DartVM
等等,所以可以提前初始化Flutter
相关的东西来达到减少第一次启动的耗时:
FlutterEngine
App
每个进程中创建第一个 FlutterEngine
实例的时候会加载 Flutter
引擎的原生库并启动 Dart VM
(VM 存活生命周期跟随进程),随后同进程中其他的 FlutterEngine
将在同一个 VM 实例上运行,而第一次启动耗时主要花费在加载 Flutter 引擎的原生库和启动 Dart VM
。所以可以提前初始化一个FlutterEngine
来减少第一次加载时的耗时。
FlutterHelper主要用于预加载FlutterEngine,初始化FlutterEngine,获取FlutterEngine。预加载时,它会在Handler空闲时对FlutterEngine初始化。
/**
* Created by : yds
* Time: 2022-07-27 10:02
*/
import android.content.Context;
import android.os.Looper;
import android.os.MessageQueue;
import io.flutter.embedding.engine.FlutterEngine;
import io.flutter.embedding.engine.FlutterEngineCache;
import io.flutter.embedding.engine.dart.DartExecutor;
import io.flutter.embedding.engine.loader.FlutterLoader;
import io.flutter.plugins.GeneratedPluginRegistrant;
public class FlutterHelper {
private FlutterHelper() {
}
//FlutterEngine缓存的key
public static final String FLUTTER_ENGINE = "flutter_engine";
//flutter初始化成功的消息
public static final String FLUTTER_ENGINE_INIT_FINISH = "flutter_engine_init_finish";
private static volatile FlutterHelper instance;
public static FlutterHelper getInstance() {
if (instance == null) {
synchronized (FlutterHelper.class) {
if (instance == null) {
instance = new FlutterHelper();
}
}
}
return instance;
}
public void preloadFlutterEngine(Context context) {
Looper.myQueue().addIdleHandler(new MessageQueue.IdleHandler() {
@Override
public boolean queueIdle() {
initFlutterEngine(context);
return true;
}
});
}
public synchronized FlutterEngine initFlutterEngine(Context context){
if (!FlutterEngineCache.getInstance().contains(FLUTTER_ENGINE)) {
//这里建议用FlutterEngineGroup来创建FlutterEngine
FlutterEngine engine = new FlutterEngine(context.getApplicationContext());
System.out.println("flutterEngine:"+engine);
GeneratedPluginRegistrant.registerWith(engine);
//Channel 注册要紧跟引擎初始化之后,否则会有在dart中调用 Channel 因为还未初始化完成而导致的时序问题
//FlutterBridge用于将Channel封装,统一提供服务
FlutterBridge.init(engine);
engine.getDartExecutor().executeDartEntrypoint(DartExecutor.DartEntrypoint.createDefault());
FlutterEngineCache.getInstance().put(FLUTTER_ENGINE, engine);
return engine;
} else {
return getFlutterEngine();
}
}
public FlutterEngine getFlutterEngine(){
if (isInitFinish()) {
return FlutterEngineCache.getInstance().get(FLUTTER_ENGINE);
} else {
try {
throw new Exception("请先初始化 FlutterEngine!");
} catch (Exception e) {
e.printStackTrace();
}
}
return null;
}
public boolean isInitFinish() {
return FlutterEngineCache.getInstance().get(FLUTTER_ENGINE) != null;
}
}
FlutterBridge主要用于管理与Flutter通信的Channel
/**
* Created by : yds
* Time: 2022-07-27 10:13
*/
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import java.util.ArrayList;
import java.util.List;
import io.flutter.embedding.engine.FlutterEngine;
import io.flutter.plugin.common.BasicMessageChannel;
import io.flutter.plugin.common.MethodCall;
import io.flutter.plugin.common.MethodChannel;
import io.flutter.plugin.common.StandardMessageCodec;
public class FlutterBridge implements MethodChannel.MethodCallHandler, BasicMessageChannel.MessageHandler<Object> {
private static final String FLUTTER_MESSAGE_CHANNEL = "message_channel";
private static final String FLUTTER_SEARCH_DATA_CHANNEL = "searchflutterfragment/searchscandata";
private static volatile FlutterBridge instance;
private static List<MethodChannel> mMethodChannels = new ArrayList<>();
public static BasicMessageChannel<Object> mChannel;
private FlutterBridge() {
}
public static FlutterBridge getInstance() {
if (instance == null) {
synchronized (FlutterBridge.class) {
if (instance == null) {
instance = new FlutterBridge();
}
}
}
return instance;
}
public static FlutterBridge init(FlutterEngine flutterEngine) {
MethodChannel channel = new MethodChannel(flutterEngine.getDartExecutor(), FLUTTER_MESSAGE_CHANNEL);
channel.setMethodCallHandler(getInstance());
mChannel = new BasicMessageChannel<>(
flutterEngine.getDartExecutor().getBinaryMessenger(), FLUTTER_SEARCH_DATA_CHANNEL,
StandardMessageCodec.INSTANCE
);
mChannel.setMessageHandler(getInstance());
mMethodChannels.add(channel);
return getInstance();
}
public static <T> void send(@Nullable T message,@Nullable final BasicMessageChannel.Reply<Object> callback){
mChannel.send(message,callback);
}
/**
* MethodChannel回调
*
* 用于接收从flutter向native发送消息
*
* @param call
* @param result
*/
@Override
public void onMethodCall(@NonNull MethodCall call, @NonNull MethodChannel.Result result) {
}
/**
* BasicMessageChannel回调
*
* 用于接收从flutter向native发送消息
*
* @param message
* @param reply
*/
@Override
public void onMessage(@Nullable Object message, @NonNull BasicMessageChannel.Reply reply) {
}
}
public class MyApplication extends Application {
public void onCreate() {
super.onCreate();
FlutterHelper.getInstance().preloadFlutterEngine(this);
}
}
FlutterHelper
预加载时会创建一个FlutterEngine
,然后会将FlutterEngine
存储在FlutterEngineCache
中。FlutterFragment
通过withCachedEngine
获取FlutterHelper
创建的FlutterEngine
,并通过build
方法创建FlutterFragment
。public class SearchFragment extends Fragment implements OnScanDataListener {
@Override
public void onCreate(@Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
initFlutterEngine();
}
@Nullable
@Override
public View onCreateView(@NonNull LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) {
return inflater.inflate(R.layout.search_fragment_layout,container,false);
}
private void initFlutterEngine(){
FlutterFragment flutterFragment = FlutterFragment.withCachedEngine(FlutterHelper.FLUTTER_ENGINE).build();
getChildFragmentManager().beginTransaction().replace(R.id.container,flutterFragment).commit();
}
@Override
public void onScanData(String data) {
FlutterBridge.send(data,new BasicMessageChannel.Reply<Object>() {
@Override
public void reply(@Nullable Object reply) {
if (reply != null) {
long endTime = System.currentTimeMillis();
System.out.println("endTime:" + endTime);
System.out.println("onScanData:" + reply.toString());
}
}
});
}
}