Flutter开发中的一些Tips(二)

我们可以看看 mounted在源码中是什么

BuildContext get context => _element;
StatefulElement _element;

/// Whether this [State] object is currently in a tree.
///
/// After creating a [State] object and before calling [initState], the
/// framework “mounts” the [State] object by associating it with a
/// [BuildContext]. The [State] object remains mounted until the framework
/// calls [dispose], after which time the framework will never ask the [State]
/// object to [build] again.
///
/// It is an error to call [setState] unless [mounted] is true.
bool get mounted => _element != null;

BuildContextElement的抽象类,你可以认为mounted 就是 context 是否存在。那么同样在回调中用到 context时,也需要判断一下mounted。比如我们要弹出一个 Dialog 时,或者在请求接口成功时退出当前页面。BuildContext的概念是比较重要,需要掌握它,错误使用一般虽不会崩溃,但是会使得代码无效。

本问题详细的代码见:点击查看

2.监听Dialog的关闭

问题描述:我在每次的接口请求前都会弹出一个Dialog 做loading提示,当接口请求成功或者失败时关闭它。可是如果在请求中,我们点击了返回键人为的关闭了它,那么当真正请求成功或者失败关闭它时,由于我们调用了Navigator.pop(context) 导致我们错误的关闭了当前页面。

那么解决问题的突破口就是知道何时Dialog的关闭,那么就可以使用 WillPopScope 拦截到返回键的输入,同时记录到Dialog的关闭。

bool _isShowDialog = false;

void closeDialog() {
if (mounted && _isShowDialog){
_isShowDialog = false;
Navigator.pop(context);
}
}

void showDialog() {
/// 避免重复弹出
if (mounted && !_isShowDialog){
isShowDialog = true;
showDialog(
context: context,
barrierDismissible: false,
builder:(
) {
return WillPopScope(
onWillPop: () async {
// 拦截到返回键,证明dialog被手动关闭
_isShowDialog = false;
return Future.value(true);
},
child: ProgressDialog(hintText: “正在加载…”),
);
}
);
}
}

本问题详细的代码见:点击查看

3.addPostFrameCallback

addPostFrameCallback回调方法在Widget渲染完成时触发,所以一般我们在获取页面中的Widget大小、位置时使用到。

前面第二点我有说到我会在接口请求前弹出loading。如果我将请求方法放在了initState方法中,异常如下:

inheritFromWidgetOfExactType(_InheritedTheme) or inheritFromElement() was called before initState() completed. When an inherited widget changes, for example if the value of Theme.of() changes, its dependent widgets are rebuilt. If the dependent widget’s reference to the inherited widget is in a constructor or an initState() method, then the rebuilt dependent widget will not reflect the changes in the inherited widget. Typically references to inherited widgets should occur in widget build() methods. Alternatively, initialization based on inherited widgets can be placed in the didChangeDependencies method, which is called after initState and whenever the dependencies change thereafter.

原因:弹出一个DIalog的showDialog方法会调用Theme.of(context, shadowThemeOnly: true),而这个方法会通过inheritFromWidgetOfExactType来跨组件获取Theme对象。

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

inheritFromWidgetOfExactType方法调用inheritFromElement

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

但是在_StateLifecyclecreateddefunct 时是无法跨组件拿到数据的,也就是initState()时和dispose()后。所以错误信息提示我们在 didChangeDependencies 调用。

然而放在didChangeDependencies后,新的异常:

setState() or markNeedsBuild() called during build. This Overlay widget cannot be marked as needing to build because the framework is already in the process of building widgets. A widget can be marked as needing to be built during the build phase only if one of its ancestors is currently building. This exception is allowed because the framework builds parent widgets before children, which means a dirty descendant will always be built. Otherwise, the framework might not visit this widget during this build phase.

提示我们页面在build时不能调用setState()markNeedsBuild()方法。所以我们需要在build完成后,才可以去创建这个新的组件(这里就是Dialog)。

所以解决方法就是使用addPostFrameCallback回调方法,等待页面build完成后在请求数据:

@override
void initState() {
WidgetsBinding.instance.addPostFrameCallback((_){
/// 接口请求
});
}

导致这类问题的场景很多,但是大体解决思路就是上述的办法。

本问题详细的代码见:点击查看

4.删除emoji

不多哔哔,直接看图:

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

简单说就是删除一个emoji表情,一般需要点击删除两次。碰到个别的emoji,需要删除11次!!其实这问题,也别吐槽Flutter,基本emoji在各个平台上都或多或少有点问题。

原因就是:

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

这个问题我发现在Flutter 的1.5.4+hotfix.2版本,解决方法可以参考:github.com/flutter/eng… 虽然只适用于长度为2位的emoji。

幸运的是在最新的稳定版1.7.8+hotfix.3中修复了这个问题。不幸的是我发现了其他的问题,比如在我小米MIX 2s上删除文字时,有时会程序崩溃,其他一些机型正常。异常如下图:

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

我也在Flutter上发现了同样的问题Issue,具体情况可以关注这个Issue :github.com/flutter/flu… ,据Flutter团队的人员的回复,这个问题修复后不太可能进入1.7的稳定版本。。

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

所以建议大家谨慎升级,尤其是用于生产环境。那么这个问题暂时只能搁置下来了,等待更稳定的版本。。。

19.07.20更新,官方发布了1.7.8+hotfix.4,修复了此问题。经过测试问题修复,大家可以放心使用了。

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

5.键盘

1.是否弹起

MediaQuery.of(context).viewInsets.bottom > 0

viewInsets.bottom就是键盘的顶部距离底部的高度,也就是弹起的键盘高度。如果你想实时过去键盘的弹出状态,配合使用didChangeMetrics。完整如下:

import ‘package:flutter/material.dart’;

typedef KeyboardShowCallback = void Function(bool isKeyboardShowing);

class KeyboardDetector extends StatefulWidget {

KeyboardShowCallback keyboardShowCallback;

Widget content;

KeyboardDetector({this.keyboardShowCallback, @required this.content});

@override
_KeyboardDetectorState createState() => _KeyboardDetectorState();
}

class _KeyboardDetectorState extends State
with WidgetsBindingObserver {
@override
void initState() {
WidgetsBinding.instance.addObserver(this);
super.initState();
}

@override
void didChangeMetrics() {
super.didChangeMetrics();
WidgetsBinding.instance.addPostFrameCallback((_) {
print(MediaQuery.of(context).viewInsets.bottom);
setState(() {
widget.keyboardShowCallback
?.call(MediaQuery.of(context).viewInsets.bottom > 0);
});
});
}

@override
void dispose() {
WidgetsBinding.instance.removeObserver(this);
super.dispose();
}

@override
Widget build(BuildContext context) {
return widget.content;
}
}

代码来自项目GSYFlutterDemo:https://github.com/CarGuo/GSYFlutterDemo

2.弹出键盘

if (MediaQuery.of(context).viewInsets.bottom == 0){
自我介绍一下,小编13年上海交大毕业,曾经在小公司待过,也去过华为、OPPO等大厂,18年进入阿里一直到现在。

深知大多数初中级Android工程师,想要提升技能,往往是自己摸索成长或者是报班学习,但对于培训机构动则近万的学费,着实压力不小。自己不成体系的自学效果低效又漫长,而且极易碰到天花板技术停滞不前!

因此收集整理了一份《2024年Android移动开发全套学习资料》,初衷也很简单,就是希望能够帮助到想自学提升又不知道该从何学起的朋友,同时减轻大家的负担。

img

img

img

img

既有适合小白学习的零基础资料,也有适合3年以上经验的小伙伴深入学习提升的进阶课程,基本涵盖了95%以上Android开发知识点,真正体系化!

由于文件比较大,这里只是将部分目录截图出来,每个节点里面都包含大厂面经、学习笔记、源码讲义、实战项目、讲解视频,并且会持续更新!

如果你觉得这些内容对你有帮助,可以扫码获取!!(备注:Android)

总结

最后为了帮助大家深刻理解Android相关知识点的原理以及面试相关知识,这里放上相关的我搜集整理的24套腾讯、字节跳动、阿里、百度2019-2021面试真题解析,我把技术点整理成了视频和PDF(实际上比预期多花了不少精力),包知识脉络 + 诸多细节

还有 高级架构技术进阶脑图、Android开发面试专题资料 帮助大家学习提升进阶,也节省大家在网上搜索资料的时间来学习,也可以分享给身边好友一起学习。

一线互联网面试专题

379页的Android进阶知识大全

379页的Android进阶知识大全

网上学习 Android的资料一大堆,但如果学到的知识不成体系,遇到问题时只是浅尝辄止,不再深入研究,那么很难做到真正的技术提升。希望这份系统化的技术体系对大家有一个方向参考。

2021年虽然路途坎坷,都在说Android要没落,但是,不要慌,做自己的计划,学自己的习,竞争无处不在,每个行业都是如此。相信自己,没有做不到的,只有想不到的。祝大家2021年万事大吉。

《Android学习笔记总结+移动架构视频+大厂面试真题+项目实战源码》,点击传送门即可获取!

入研究,那么很难做到真正的技术提升。希望这份系统化的技术体系对大家有一个方向参考。

2021年虽然路途坎坷,都在说Android要没落,但是,不要慌,做自己的计划,学自己的习,竞争无处不在,每个行业都是如此。相信自己,没有做不到的,只有想不到的。祝大家2021年万事大吉。

《Android学习笔记总结+移动架构视频+大厂面试真题+项目实战源码》,点击传送门即可获取!
  • 4
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值