flutter面试题
一、flutter与原生通信,三种通道的区别
1.1 MethodChannel
Flutter与Native端相互调用,调用后返回结果
可以Native端主动调用,也可以Flutter主动调用,属于双向通信
此种方式最为常见,Native端调用需要在主线程中执行
1.2 BasicMessageChannel
用于使用指定的编解码器对消息进行编码和解码
属于双向通信,可以以Native端主动调用,也可以Flutter主动调用
1.3 EventChannel
用于数据流(event stream)的通信,Native端主动发送数据给Flutter
通常用于状态端监听,比如网络变化、传感器数据等
原文链接:https://blog.csdn.net/Calvin_zhou/article/details/118888030
二、flutter自定义组件,生命周期
Flutter的生命周期包含一下几个阶段:
CreateState 该函数为StatefulWidget创建State时调用的方法,当StatefulWidget被调用时候会立即调用此方法。
initState 该方法为State初始化调用,因此在此期间可以执行变量的初始化,还可以进行与服务端的初始化,获取到服务端数据之后调用setState方法更新组件。
didChangeDependencies 该函数是在该组件依赖的全局State发生变化的时候调用。
build 该函数主要是渲染Widget,会被调用多次,最好只做返回Widget相关的事情。
reassemble 只要是提供开发阶段使用,只有在debug模式下热重载才会调用。可以添加一些代码来调试。
didUpdateWidget 此方法在组件重新构建,比如热更新,父组件发生Build时候调用此方法,其次此方法会导致本组件的build方法被调用。
deactivate 在组件被移除时候调用,如果组件被移除,未被插入到其他组件。那么会调用dispose永久移除。
1、initState
调用次数:1次
插入渲染树时调用,只调用一次,widget创建执行的第一个方法,这里可以做一些初始化工作,比如初始化State的变量。
2、didChangeDependencies
调用次数:多次
初始化时,在initState()之后立刻调用
当依赖的InheritedWidget rebuild,会触发此接口被调用
实测在组件可见状态变化的时候会调用
3、build
调用次数:多次
初始化之后开始绘制界面
setState触发的时候会
4、didUpdateWidget
调用次数:多次
组件状态改变时候调用
5、deactivate
当State对象从树中被移除时,会调用此回调,会在dispose之前调用。
页面销毁的时候会依次执行:deactivate > dispose
6、dispose
调用次数:1次
当State对象从树中被永久移除时调用;通常在此回调中释放资源。
7、reassemble
在热重载(hot reload)时会被调用,此回调在Release模式下永远不会被调用
原文链接:https://blog.csdn.net/yoonerloop/article/details/121003373
1.WidgetsBindingObserver
和App生命周期有关AppLifecycleState
1、resumed
可见并能响应用户的输入,同安卓的onResume
2、inactive
处在并不活动状态,无法处理用户响应,同安卓的onPause
3、paused
不可见并不能响应用户的输入,但是在后台继续活动中,同安卓的onStop
下面是生命周期:
初次打开widget时,不执行AppLifecycleState的回调;
按home键或Power键, AppLifecycleState inactive---->AppLifecycleState pause
从后台到前台:AppLifecycleState inactive--->ApplifecycleState resumed
back键退出应用: AppLifecycleState inactive--->AppLifecycleState paused
原文链接:https://blog.csdn.net/yoonerloop/article/details/121003373
//初始化一些变量
void onCreate() {}
//onResume 只要页面切换到栈顶,都会调用此方法
void onResume() {
_isResume = true;
_isPause = false;
}
//页面被覆盖,暂停
void onPause() {
_isResume = false;
_isPause = true;
}
void onDestroy() {}
LifeCycleInnerState
2.RouteAware
监听路由变化
RouteObserver 是一个配合RouteAware的一个类,通过这个类可以通知到当前页面应该执行那种生命周期方法,否则只混入RouteAware是不能执行的。另外还有RouteObserver需要注册在MaterialApp中,这样才能在导航的过程中执行到对应的生命周期方法。navigatorObservers
@override
void didPush() {
super.didPush(); //从其他页面跳转到当前页面
log("didPush");
_isTop = true;
}
@override
void didPushNext() { //从当前页面跳转到下一页之后才会调用?
super.didPushNext();
log("didPushNext");
onPause(); //在本页面执行onPause()
_isTop = false;
}
@override
void didPop() { //从当前页面退回当上一页面
super.didPop(); //pop
onPause();//在当前页执行onPause()
}
@override
void didPopNext() {
super.didPopNext();//从其他页面Pop之后,进入到当前页面
onResume();//在当前页面执行onResume()
_isTop = true;
}
原文链接:https://blog.csdn.net/happiness365/article/details/122782217
三、flutter树结构
Widget树、Element树、RenderObject树
并不是所有的Widget都会被独立渲染!只有继承RenderObjectWidget的才会创建RenderObject对象
每一个Widget都会创建一个Element对象
隐式调用createElement方法。Element加入Element树种
它会创建三种Element
1.RenderElement主要是创建RenderObject对象
继承RenderObjectWidget的Widget会创建RenderElement
创建RanderElementFlutter会调用mount方法,调用createRanderObject方法
2.StatefulElement继承ComponentElement
StatefulWidget会创建StatefulElement
调用createState方法,创建State将Widget赋值给state调用state的build方法 并且将自己(Element)传出去
build里面的context就是Widget的Element!
3.StatelessElement继承ComponentElement
StatelessWidget会创建StatelessElement
主要就是调用build方法 并且将自己(Element)传出去
四、flutter 状态管理,provider
状态管理就是一些变量的管理,而这些变量需要在多个路由界面中重复使用,所以就有了状态管理。
如果多个界面需要重复数据时,当这些界面频繁跳转时,没有全局状态管理,那就需要每次跳转路由界面都需要传值一次达到保存数据的目的,当有了全局状态管理,每次需要读取或者改变这些数据时,则可以调用公用方法获取或修改,因此可以大大减少工作量并提升应用性能
一个model类可以有多个属性,一个app可以有多个model类
全局管理类,不见得用model结尾,但是我个人喜欢用model来存储数据
model类必须要继承ChangeNotifier类,否则无法刷新数据
model管理的状态,只有get方法,修改他的值是通过单独的方法进行修改的,在修改后要调用notifyListeners方法
链接:https://www.jianshu.com/p/7d392f696de3
五、Future是什么
Future代表异步执行
async:在方法体前面是使用,定义该方法为一个异步方法。
await:等待并获得异步表达式的执行结果,并且给关键字只能在async修饰的方法中。
Future是单线程,先执行完全部微任务,再执行队列任务
Future修饰的关键字,会将事件加入到队列任务中
Future如何获取异步的值:通过then()方法
Future如何处理异常:通过catchError()或者在then()中传入命名参数onError
async和wait的关键的作用是什么:async声明一个异步方法,wait等待异步任务完成;简单来讲就是同步的方式编写异步代码。
如何捕获和处理async中的异常:需要使用try/catch来捕获以及处理程序运行中的异常。
原文链接:https://blog.csdn.net/mrRuby/article/details/122563629
六、UI或文本溢出
文本用TextOverflow进行溢出属性处理
列表溢出,使用Wrap(//流式布局处理
在text 外层包裹一个Expanded 它会将宽高设定为余下空间
1,Row报overflowed的解决办法
在要展示内容外包一层Expanded
2,Column报overflowed的解决办法
在Column外包一层SingleChildScrollView
在Scaffold下设置resizeToAvoidBottomInset : false
七、flutter性能优化
1.widget build()方法避免执行重复耗时的非必要操作
避免在widget或者state的build()方法中进行重复且耗时的非必要工作,因为当父 widget 重建时,子 widget 的 build() 方法会被频繁地调用。因此确保非必要的耗时工作不放在build()方法中。
2.控制widget setState()的重建范围
在StatefulWidget中调用setState()会引起该widget的重建,会调用state的build()方法。当一个页面只有一个StatefulWidget,把全部widget的状态都放在这个StatefulWidget,并且该StatefulWidget为页面最顶端的父widget时,setState方法会让整个页面的widget重建。因此,将一个页面中的widget进行多个StatefulWidget的状态划分,每个StatefulWidget只负责自己的状态维护,将大大缩小flutter页面绘制范围。
3.控制widget重建次数
不会改变的widget使用const,如Text、Icon、Image等,这样可以复用这部分widget,不会导致widget重建
动画使用AnimatedBuilder时,将不需要动的子widget赋值给child参数,builder方法中使用该child,可以做到复用子widget,以避免在动画过程中重建其后代 widget。
使用CustomPaint自定义组件的时候,使用重写shouldRepaint方法,返回false即不重绘,true为重绘,我们可以根据条件返回true,减少自定义组件的重绘次数
4.尽量避免saveLayer操作
saveLayer方法是Flutter框架中最重量的操作之一。更新屏幕时这个方法很有用,但它可能使应用变慢,如果不是必须的话,应该避免使用这个方法。即便没有显式地调用saveLayer,也可能在其他操作中间接调用了该方法。
有两个方法可以检查页面是否使用saveLayer,
1.可以使用在MeterialApp中时使用checkerboardOffscreenLayers属性开关来检查当前界面是否使用了saveLayer,打开开关之后,运行应用并检查是否有图像的轮廓闪烁。如果有新的帧渲染的话,容器就会闪烁;
2.使用flutter screenshot --type=skia --observatory-url=这里填timeline的观察台地址,生成skp文件,再上传到https://debugger.skia.org/,就可详细分析页面中的saveLayer的调用,推荐该方法,第一种方法有的saveLayer无法检查出来。
在官网中可以看到,以下组件会触发saveLayer,应尽量避免使用,寻找其他代替。透明度(Opacity)、裁剪(clipping)、阴影(shadows)以及文字(Text)
5.使用懒加载、按需加载模型Slive
滚动列表中SingleChileScrollView不支持Slive,会直接加载整个子widget,如果滑动部分很长,请使用ListView、gridView等支持按需加载模型的列表,并且使用ListView.builder或者ListView.separated加载子项。
6.使用RepaintBoundary
使用RepaintBoundary,给页面设置重绘范围,将提高我们的性能。比如页面滑动不需要重绘动画,使用RepaintBoundary包住我们的动画widget,页面滑动将不会导致动画重绘。还可以用该widget包住我们的图片,做图片缓存,ListView里面就使用了RepaintBoundary来包住item,缓存item。
7.复用Element
element tree是flutter三棵树之一,我个人把他当作渲染树的manager,widget内部有个canUpdate方法。
原文链接:https://blog.csdn.net/weixin_42468452/article/details/120534954
八、flutter插件开发,原生混合开发
iOS用framework或pod
安卓用aar包接入
使用flutterBooost框架
解决跳转全屏flutter会出现引导页
路由问题,pod的时候将flutterBooost的监听和flutterController释放调
九、flutter网络请求,dio优点
dio是一个强大的Dart Http请求库,支持Restful API、FormData、拦截器、请求取消、Cookie管理、文件上传/下载、超时、自定义适配器等...可以说是覆盖了所有涉及到的网络请求。
原生HttpClient发起网络请求非常的复杂,很多东西还需自己手动处理。如果涉及到上传、下载、断点续传等那肯定非常繁琐
每个 Dio 实例都可以添加任意多个拦截器,他们组成一个队列,拦截器队列的执行顺序是FIFO先进先出原则。通过拦截器你可以在请求之前、响应之后和发生异常时(但还没有被then或catchError处理)做一些统一的预处理操作。
共有 0 条评论