瞎拍 - 留沪过年
过年前疫情闹得凶,吓得我把回家票给退了……
谁知上海还是比较给力,没有扩散,却再买不着回去的票,只好一边上班一边摸鱼用盒马囤了许多年货。
就这样,一人一猫留沪过年。
细雨声中,捣鼓好了一个人的年夜饭。
一边抢着微信红包,一遍强迫猫陪我看拜年祭。
年初二天气不错,出门找找上海的年味,不然一个人在家快要发霉了。
上海哪人最多最热闹?当然是外滩了。
几个月没来外滩了,乍浦路桥这段竟已被改造成游人走廊。
过年前疫情闹得凶,吓得我把回家票给退了……
谁知上海还是比较给力,没有扩散,却再买不着回去的票,只好一边上班一边摸鱼用盒马囤了许多年货。
就这样,一人一猫留沪过年。
细雨声中,捣鼓好了一个人的年夜饭。
一边抢着微信红包,一遍强迫猫陪我看拜年祭。
年初二天气不错,出门找找上海的年味,不然一个人在家快要发霉了。
上海哪人最多最热闹?当然是外滩了。
几个月没来外滩了,乍浦路桥这段竟已被改造成游人走廊。
Flutter 项目里用到了 http2 包 (https://pub.dev/packages/http2) 。但官方似乎没有支持 http proxy ,转念一想,似乎也对,proxy 这层不属于 http2 协议该负责实现的事。
研究了一下 http/1.1 tunnel proxy 的协议(RFC 2817)发现其实挺简单的。
这里直接放出示例了,仅供参考哦(需要登录的 proxy 就留给你自己实现了)。
1 | import 'dart:async'; |
观前提醒:本文假设你已经有一定的 Flutter 开发经验,对Flutter 的 Widget,RenderObject 等概念有所了解,并且知道如何开启 DevTools。
现有一个简单的汽泡动画需要实现,如下图:
当看到这个效果图的时候,很快啊,啪一下思路就来了。涉及到动画,有状态,用 StatefulWidget
,State 里创建一个 AnimationController
,用两个 Container
对应两个圈,外圈的 Container
的宽高监听动画跟着更新就行。
代码如下:
1 | const double size = 56; |
logging
Add logging
to pubspec.yaml
file:
1 | dependencies: |
Logger
Initialize Logger
before runApp()
in main.dart
file:
1 | import 'logging.dart'; |
1 | import 'package:logging/logging.dart'; |
dart:developer
Logger is a producer
, but it will not post any log records if no one is listening.
Print to console:
1 | Logger.root.onRecord.listen((event) { |
Save to file:
1 | File logFile = ... |
It’s strongly recommended to use dart:developer
for logging:
1 | import 'dart:developer' as developer; |
Flutter 上应该怎么请求http?很简单,直接用 dart:io
包下的 HttpClient,如下代码:
1 | HttpClient client = HttpClient(); |
但你肯定也发现了 dart:io
的 HttpClient
所提供的API太过底层了,所以一般不会直接用,而是用Dart官方提供的 http 包(package:http),如下代码:
1 | import 'package:http/http.dart'; |
或者有很多人喜欢的 dio。
但无论怎么封装API,底层都还是 dart:io
里的HttpClient
。
你可能一直有疑问,不是说 Flutter 是单线程的,那 http 请求难道不会卡住 UI 线程,导致 UI 无响应吗?
一般的,在 Flutter APP 里请求 HTTP 使用的是官方提供的 http 包。
1 | import 'package:http/http.dart' as http; |
但是,有一个问题,在 Android 或者 iOS 上运行 Flutter APP,系统里配置的 HTTP 代理并不生效?
比如在使用 Charles 这种工具通过 HTTP 代理调试 API 请求时候,会发现 Flutter 的 http 请求没有按预期走代理,无论是 Http 还是 Https。
哔哩哔哩漫画APP实践Flutter也有大半年时间了,我针对线上收集到的错误进行分析,挑选出了一些有一般代表性的错误,列在本文,可供实践 Flutter 的初学者们作为一点参考。
典型错误信息:NoSuchMethodError: The method 'markNeedsBuild' was called on null.
这个错误常出现在异步任务(Future)处理,比如某个页面请求一个网络API数据,根据数据刷新 Widget State。
异步任务结束在页面被pop之后,但没有检查State 是否还是 mounted
,继续调用 setState
就会出现这个错误。
一段很常见的获取网络数据的代码,调用 requestApi()
,等待Future从中获取response
,进而setState
刷新 Widget:
1 | class AWidgetState extends State<AWidget> { |
response
的获取为async-await
异步任务,完全有可能在AWidgetState
被 dispose
之后才等到返回,那时候和该State
绑定的 Element
已经不在了。故而在setState
时需要容错。
setState
之前检查是否 mounted
1 | class AWidgetState extends State { |
这个mounted
检查很重要,其实只要涉及到异步还有各种回调(callback),都不要忘了检查该值。
比如,在 FrameCallback
里执行一个动画(AnimationController):
1 |
|
AnimationController
有可能随着 State 一起 dispose
了,但是FrameCallback
仍然会被执行,进而导致异常。
又比如,在动画监听的回调里搞点事:
1 |
|
同样的在_handleAnimationTick
被回调前,State 也有可能已经被dispose
了。
如果你还不理解为什么,请仔细回味一下Event loop
还有复习一下 Dart 的线程模型。
最近 2019-nCoV 疫情漫延,天天闲在家也没事干,突然觉得非常孤单寂寞冷,今天回顾了一下我相亲这么多回还是孑然一身的原因。以下为正文。。
每逢假期,回老家相亲是不可回避的乡亲们茶余饭后喜闻乐见的节目。
素未谋面的两人抽出时间,凑在一起碰过面之后,如果一方觉得可以进一步发展试试,但却不知对方的态度,接下来就会纠结:是主动表态还是被动等待。
一旦开始了选择,这其实可以将理性的双方看作处于一场非零和博弈中了。
双方组合起来有如下四种策略:
🧑主动 | 🧑等待 | |
---|---|---|
👨主动 | (2,2) | (0,3) |
👨等待 | (3,0) | (1,1) |
在实际“博弈”中,理性的🧑👨双方都会站在自己的角度,只考虑到自己的最佳回报,不约而同地选择了等待(“纳什均衡”),亦即这场相亲最后不了了之,bad end。