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自定义组件,生命周期

image.png

image.png

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

image.png

五、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处理)做一些统一的预处理操作。

链接:https://www.liujunmin.com/flutter/dio_analysis.html

版权声明:
作者:感冒的梵高
链接:https://www.techfm.club/p/51145.html
来源:TechFM
文章版权归作者所有,未经允许请勿转载。

THE END
分享
二维码
< <上一篇
下一篇>>