当前位置:网站首页>【Flutter】混合开发之Flutter预加载解决第一次加载页面缓慢问题
【Flutter】混合开发之Flutter预加载解决第一次加载页面缓慢问题
2022-07-30 00:26:00 【It一zhai男】
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来减少第一次加载时的耗时。
1. 提前预加载
1.1 FlutterHelper
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;
}
}
1.2 FlutterBridge
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回调 * <p> * 用于接收从flutter向native发送消息 * * @param call * @param result */
@Override
public void onMethodCall(@NonNull MethodCall call, @NonNull MethodChannel.Result result) {
}
/** * BasicMessageChannel回调 * <p> * 用于接收从flutter向native发送消息 * * @param message * @param reply */
@Override
public void onMessage(@Nullable Object message, @NonNull BasicMessageChannel.Reply reply) {
}
}
1.3 使用
- 首先在Application中进行预加载
public class MyApplication extends Application {
public void onCreate() {
super.onCreate();
FlutterHelper.getInstance().preloadFlutterEngine(this);
}
}
2. 全局使用同一个FlutterEngine
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());
}
}
});
}
}
边栏推荐
- At the age of 29, I was fired from a functional test. Can't find a job after 2 months of interviews?
- Getting Started with Sentinel
- 更换可执行文件glibc版本的某一次挣扎
- 【励志】科比精神
- 消息中间件解析 | 如何正确理解软件应用系统中关于系统通信的那些事?
- ZLMediaKit源码学习——UDP
- Worthington解离酶:中性蛋白酶(分散酶)详情解析
- Finding a 2D Array
- The strongest JVM in the whole network is coming!(Extreme Collector's Edition)
- ZLMediaKit源码分析 - NotifyCenter
猜你喜欢

高德地图jsapi不生效 INVALID_USER_SCODE

谷歌浏览器(google)设置翻译中文,翻译选项不生效或没有弹出翻译选项

“ 我是一名阿里在职9年软件测试工程师,我的经历也许能帮到处于迷茫期的你 ”

EA&UML日拱一卒-多任务编程超入门-(9)线程同步

抖音短视频流量获取攻略,掌握好这些一定可以出爆款

『牛客|每日一题』走迷宫

Worthington木瓜蛋白酶&胰凝乳蛋白酶&脱氧核糖核酸酶 I

UE4 makes crosshair + recoil

First Normal Form, Second Normal Form, Third Normal Form

【集训DAY16】ALFA【凸壳】【计算几何】
随机推荐
循环神经网络(RNN)
rk-boot framework combat (1)
Worthington木瓜蛋白酶&胰凝乳蛋白酶&脱氧核糖核酸酶 I
抖音短视频流量获取攻略,掌握好这些一定可以出爆款
Go language serialization and deserialization and how to change the uppercase of the json key value to lowercase if the json after serialization is empty
【MySQL系列】MySQL数据库基础
更换可执行文件glibc版本的某一次挣扎
Docker install MySQL8.0
At the age of 29, I was fired from a functional test. Can't find a job after 2 months of interviews?
kubernets学习 -环境搭建
Worthington dissociating enzyme: detailed analysis of neutral protease (dispase)
Ubuntu中使用SQLite
定时器学习
Elephant Swap: Provide arbitrage space in the crypto market with ePLATO
i.MX6U-driver development-3-new character driver
新媒体运营必备的4个热点查询网
经典论文-SqueezeNet论文及实践
工厂模式
The strongest JVM in the whole network is coming!(Extreme Collector's Edition)
Print linked list from end to beginning