Flutter项目遇到的问题及解决方法记录
Posted
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Flutter项目遇到的问题及解决方法记录相关的知识,希望对你有一定的参考价值。
参考技术A 问题原因:版本大小原因解决方案:点击ios文件夹->点击podfile修改如下(亲测实用已解决)
解决方案:
删除IOS工程中的Podfile.lock文件,重新pod install(继续执行Flutter run操作)即可解决。
问题原因:没有配置safety相关
解决方案:可以直接在命令行中执行:
然后在Additional run args 这行键入一下命令即可。
问题原因:xcode版本更新导致的
解决方案:将爆红处一行隐藏,运行,点击fix即可,会显示正确位置就解决了。
解决方法:
1、找到第一个爆红文件,将311行问号后面的Colors.white删除即可
2、 在相同的文件夹内找到第二个爆红文件,找到106行,删除super.addAllowedPoint这一行即可。
造成原因分析:还不清楚
群友帮助:经常出现,重启电脑多试试
解决方案:暂未找到
flutter 单线程异步 及 isolate 使用过程遇到的问题
遇到两个问题:
- 官方 子 isolate 内不能使用插件. 解决方案: 使用 isolate_handler / flutter_isolate 代替官方 isolate 参考链接
- 子 isolate 处理完耗时操作, 传递结果给主 isolate 的方法: void send(Object? message); 耗时严重, 达秒级, 顿了一下, 页面才刷新的感觉( 未解决 )
Dart 单线程异步怎么实现的?
Dart 是单线程语言. Flutter 依赖于Dart
Dart的 “线程” 是指 isolate.
isolate 与线程的区别: isolate 之间是内存独立的, isolateA 不能访问isolateB的内存数据.
Future 可以实现异步.异步但串行非并发执行任务
单线程并不是说 Dart 只有一个线程! Dart可以创建子 isolate 实现多线程.
loop内有两个FIFO队列
- microask queue
- event queue (里面就是Future任务)
前者执行优先级高于后者, 如图
future / async / await
1. future 是Future 的实例对象, future 代表一个异步操作的结果, 它有两种状态: 未完成和已完成.
2. await 可以修饰函数/, 如果该函数返回值为Future 类型, 则会阻塞当前流程, 等待被修饰的函数执行完成后继续执行后续代码. 函数内使用 await 的前提是该函数是一个 async 函数. 也就是说 await 要和 async 配对使用.
3. 但是 async 函数内可以没有 await 关键字.
总结: await future 会阻塞流程
一: 关于async 函数:
函数内有阻塞流程(await future)的操作, 则函数会返回一个 future 实例
(1) 如果该函数本身有返回值, 比如类型为T, 则返回类型为Future<T.>
(2) 如果该函数本身没有返回值, 则返回类型为 Future<void.>
比如下面的 funcTest 函数会返回 Future<void.>
funcTest() async
await Future(()
print('funcTest end');
);
二 async 和 await 的执行流程
一个async函数同步运行直到第一个 await关键字。这意味着在async函数体内,第一个await关键字之前的所有同步代码都会立即执行。
版本说明: 在 Dart 2.0 之前,async函数立即返回,不执行async函数体内的任何代码。
例子:
void main() async
print('main begin');
funcB();
print('main end');
funcB() async
print('funcB begin');
await Future.delayed(Duration(seconds: 2), ()
print('funcB delayed over');
);
print('funcB end');
funcB 虽然是异步函数, 但是在main函数执行到funcB时并不会跳过去打印’main end’, 而是继续执行funcB , 直到遇到funcB的第一个await关键字后返回.
打印结果:
main begin
funcB begin
main end
funcB delayed over
funcB end
Future 实现异步
官方event-loop描述
1. 立刻把任务加入 event queue, 用 Future():
// Adds a task to the event queue.
new Future(()
// …code goes here…
);
2. some time 后把任务加入(并非执行!) event queue用 Future.delayed():
// After a one-second delay, adds a task to the event queue.
new Future.delayed(const Duration(seconds:1), ()
// …code goes here…
);
注意: Future 或 Future.delayed 的返回值是Future<T.>类型还是 Future<void.> 类型, 取决于执行函数有无返回值, 有返回值就是前者, 无返回值就是后者; 可以把执行函数理解成上文的异步函数
执行main函数:
- main begin
- funcA 是同步函数, 正常执行
- funcA
- 这时到了funcB, 进入函数内同步执行, 直到遇到第一个await返回. 同时把函数内Future.delay添加到 event queue 队尾. 并立刻往下执行 funcC
- funcB begin
- funcC 是 async 函数, 虽然调用时使用了await 关键字, 但是 funcC 函数内部没有阻塞流程的代码, 不会返回future. 这里 await funcC(); 等同于 funcC();
- funcC begin
- 2s后把执行函数加入 event loop
- funcC end
- 5. funcD 与 funcC 不同的是, 方法内的 Future.delayed 调用时使用了 await, 则funcD 返回一个 future, 且会阻塞funcD 函数体, 等Future.delayed 执行函数完成才会打印 ‘funcD end’,又因为 main 函数 await funcD(); 所以要等 funcD 函数全部执行完成, 才会打印 'main end’
- funcD begin
- 2s后把执行函数加入 event loop
- Future.delay 执行函数完成 打印 funcD end
- main 函数处于等待 funcD的状态, 开始loop, 因为我们没有往microtask queue 添加任务, 所以串行执行(非并发!!!) event queue
- 此时 event queue 的任务:
funcB.Future.delayed funcC.Future.delayed funcD.Future.delayed
- 此时 event queue 的任务:
FIFO原则
(1) funcB delayed over
(2) funcB end 这里我的理解是, ‘funcB end’ 被放在了’funcB delayed over’的 then 回调里, ‘funcB delayed over’ 完成后立刻执行 ‘funcB end’ 然后才 loop下一个任务
(3) funcC delayed over
(4) funcD delayed over
(5) mainEnd
void main() async
print('main begin');
funcA();
funcB();
await funcC();
await funcD();
print('main end');
funcA()
print('funcA');
funcB() async
print('funcB begin');
// 2s后把执行函数加入 event loop, 且执行函数变成完成状态才会执行下面的 'funcB end'
await Future.delayed(Duration(seconds: 2), ()
print('funcB delayed over');
);
print('funcB end');
funcC() async
print('funcC begin');
// 2s后把执行函数加入 event loop
Future.delayed(Duration(seconds: 2), ()
print('funcC delayed over');
);
print('funcC end');
funcD() async
print('funcD begin');
// 2s后把执行函数加入 event loop, 且执行函数变成完成状态才会执行下面的 'funcD end'
await Future.delayed(Duration(seconds: 2), ()
print('funcD delayed over');
);
print('funcD end');
isolate
我们平时写的代码就运行在flutter创建好的UI线程. 当运行耗时代码时页面会有卡顿感, 就是掉帧了.
解决方案: 开辟新线程处理耗时操作, 把处理结果传给 UI 线程刷新页面.
Dart 开辟新线程的方式是使用 isolate.
isolate 与普通线程的区别在于: isolate之间是内存隔离的!!!.
比如: isolate A 内不能访问 isolate B 的变量
此时好像就结束了, 但是! 官方isolate有一个致命局限性…
我们自己创建的isolate内是没办法使用插件的. 原因是Platform-Channel的通信只能在主isolate内执行
在Stack Overflow 发现两个插件, 可以完美解决这个问题:
- isolate_handler
- flutter_isolate
但是当我感觉终于要看到胜利的曙光时我发现,
这个方法耗时达秒级(把子isolate执行完毕的结果发送给主isolate)
abstract class SendPort implements Capability
/// Sends an asynchronous [message] through this send port, to its
/// corresponding `ReceivePort`.
///
/// The content of [message] can be: primitive values
/// (null, num, bool, double, String), instances of [SendPort],
/// and lists and maps whose elements are any of these.
/// List and maps are also allowed to contain cyclic references.
///
/// In the special circumstances when two isolates share the same code and are
/// running in the same process (e.g. isolates created via [Isolate.spawn]),
/// it is also possible to send object instances (which would be copied in the
/// process). This is currently only supported by the
/// [Dart Native](https://dart.dev/platforms#dart-native-vm-jit-and-aot)
/// platform.
///
/// The send happens immediately and doesn't block. The corresponding receive
/// port can receive the message as soon as its isolate's event loop is ready
/// to deliver it, independently of what the sending isolate is doing.
void send(Object? message);
如果这样, isolate的使用场景就变得很少了, 也只能后台任务不需要刷新页面的情况下使用了
参考: futures-isolates-event-loop
以上是关于Flutter项目遇到的问题及解决方法记录的主要内容,如果未能解决你的问题,请参考以下文章
flutter 单线程异步 及 isolate 使用过程遇到的问题