flutter面试题

作者: 你飞跃俊杰 | 来源:发表于2022-09-26 11:52 被阅读0次

    一、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</blockcode>

    //初始化一些变量
    
    void onCreate() {}
    
    //onResume 只要页面切换到栈顶,都会调用此方法
    
    void onResume() {
    
    _isResume = true;
    
    _isPause = false;
    
    }
    
    //页面被覆盖,暂停
    
    void onPause() {
    
    _isResume = false;
    
    _isPause = true;
    
    }
    
    void onDestroy() {}</blockcode> 
    

    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</blockcode>

    三、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)传出去</blockcode> 
    

    四、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

    相关文章

      网友评论

        本文标题:flutter面试题

        本文链接:https://www.haomeiwen.com/subject/jmunortx.html