• Flutter调研-Flutter基础知识、安装与demo


    工作需要,因客户端有部分页面要使用flutter编写,需要QA了解一下flutter相关知识,因此,做了flutter调研,包含安装,基础知识与demo编写,第二部分是安装与环境配置。

    ——

    Flutter 是 Google推出并开源的移动应用开发框架,主打跨平台、高保真、高性能

    想要更全面的了解Flutter,首先我们需要了解什么是跨平台框架

    一、跨平台技术以及其他的跨平台框架

    原生应用程序:指某一个移动平台(比如iOS或安卓)所特有的应用,使用相应平台支持的开发工具和语言,并直接调用系统提供的SDK API。

    优点可访问平台全部功能,如GPS、摄像头;性能高,可实现复杂动画,用户体验好。

    缺点动态化更新难度大,需要升级发版更新(或者hotfix);由于双平台,开发测试成本大。

    针对原生开发这两个缺点,诞生了一些跨平台的动态化框架

    目前主要有三类

    • H5+原生(混合开发框架:Cordova、Ionic、微信小程序)
    • JavaScript开发+原生渲染 (React Native、Weex、快应用)
    • 自绘UI+原生(QT for mobile、Flutter)

    1、H5+原生

    也被称为hybrid开发,这类在各大app很常见,我们app当然也有使用

    主要原理:将APP内的部分内容通过H5来实现,通过原生的网页加载控件WebView 来加载,由h5实现动态更新

    H5代码是运行在WebView中,而WebView实质上就是一个浏览器内核,像位于一个权限受限的沙箱中,所以对于大多数系统能力没有访问权限,

    混合框架一般都会在原生代码中预先实现一些访问系统能力的API, 然后暴露给WebView以供JavaScript调用。

    缺点是性能不好,复杂用户界面或者动画实现上会困难

    2、JavaScript开发+原生渲染

    React Native (简称RN)是Facebook于2015年4月开源的跨平台移动应用开发框架,RN使用Javascript语言
    RN和React原理相通,并且Flutter也是受React启发,思想相通

    React Native是原生控件渲染,所以性能会比混合应用中H5好很多,但是受限于js是脚本语言,执行效率有待提高,而且渲染依赖于原生控件,也依赖于系统更新,会受原生UI系统限制

    3、自绘UI+原生

    Flutter属于这种类型的跨平台框架,通过在不同平台实现一个统一接口的渲染引擎来绘制UI,而不依赖系统原生控件,所以可以做到不同平台UI的一致性。

    自绘引擎解决的是UI的跨平台问题,如果涉及其它系统能力调用,依然要涉及原生开发

    (我们测试时,可以注意下假如要调取原生的权限应用时的场景)

    优点是性能高,灵活易维护;缺点是无法进行动态化更新,还是要升级更新

    综上:

    技术类型UI渲染方式性能开发效率动态化框架代表
    H5+原生 WebView渲染 一般 支持 Cordova、Ionic
    JavaScript+原生渲染 原生控件渲染 支持 RN、Weex
    自绘UI+原生 调用系统API渲染 Flutter高, QT低 默认不支持 QT、Flutter

    二、Flutter

    总结上一节,Flutter的优点是

    • 一套代码双平台运行,节约成本
    • 热重载功能提高开发效率(后续会通过demo具体展示热重载)
    • 采用自带的引擎进行渲染绘制,性能高

    Flutter框架图

    (核心只有一层轻量的C/C++代码。Flutter在Dart中实现了其它大部分系统(组合、手势、动画、框架、widget等), 开发人员可以轻松地进行读取、更改、替换或移除)

    Flutter的一些基础知识

    1、Flutter使用的开发语言:Dart

    Dart是面向对象的语言,有垃圾回收机制,借鉴了Java和JavaScript,静态语法方面和Java非常相似,如类型定义、函数声明、泛型等,而在动态特性方面又和JavaScript很像,如函数式特性、异步支持等。

    (具体在Dart语言里展开细说)

    2、热重载(demo演示)

    • 运行后更改代码,不要按“停止”按钮;,让应用继续运行;

    • 调用 Save (cmd-s / ctrl-s),或者点击 热重载按钮 (带有闪电⚡️图标的按钮),此时查看设备已经即时更改为新代码

    3、一切都是widget

    在Android和iOS上,部件所对应的就是各种View类。
    Flutter采用了不同的概念,部件不仅仅是结构化的元素。Flutter的部件架构更多地使用了组合,而不是继承,所以部件架构更加强大和灵活。Flutter官方文档写道:
    在Flutter里,行为也是部件(如GestureDetector)。InheritedWidget可用于进行状态管理,AnimatedWidget可用于构建动画。

    三、Dart单线程模型

    在Java中,如果程序发生异常且没有被捕获,那么程序将会终止,但是这在Dart或JavaScript中则不会;

    Java是多线程模型的编程语言,任意一个线程触发异常且该异常未被捕获时,就会导致整个进程退出。但Dart和JavaScript不会,它们都是单线程模型。

    在Dart中,所有的外部事件任务都在事件队列中,如IO、计时器、点击、以及绘制事件等,而微任务通常来源于Dart内部,并且微任务非常少,之所以如此,是因为微任务队列优先级高,如果微任务太多,执行时间总和就越久,事件队列任务的延迟也就越久,对于GUI应用来说最直观的表现就是比较卡,所以必须得保证微任务队列不会太长。值得注意的是,我们可以通过Future.microtask(…)方法向微任务队列插入一个任务。

    在事件循环中,当某个任务发生异常并没有被捕获时,程序并不会退出,而直接导致的结果是当前任务的后续代码就不会被执行了,也就是说一个任务中的异常是不会影响其它任务执行的。

    四、State的生命周期

    State初始化时会依次执行 : 构造函数 > initState > didChangeDependencies > Widget build , 此时页面加载完成

    ===================================

    在mac上实现flutter的从安装到运行,以下基于Android Studio,xcode相关设置后续补充

    1、首先,国内访问flutter有时会有限制,以防万一,使用镜像


    将以下环境变量添加到用户环境变量里
    export PUB_HOSTED_URL=https://pub.flutter-io.cn
    export FLUTTER_STORAGE_BASE_URL=https://storage.flutter-io.cn

    2、官网下载flutter安装包


    https://flutter.dev/docs/development/tools/sdk/releases?tab=macos#macos
    选择稳定版Stable channel,下载后解压到你想安装的目录里,如:
    cd ~/development
    unzip ~/Downloads/flutter_macos_v0.5.1-beta.zip
    临时添加到flutter到path中
    export PATH=`pwd`/flutter/bin:$PATH

    3、终端执行 flutter doctor


    (提示command not fount 的话:1不在flutter文件夹所在目录下2未设置PATH环境变量)
    根据指示查看当前是否有缺失
    安卓需要安装androif Studio,IOS需要安装xcode
    如果提示Android licenses 不被信任或者unkown,按照提示执行
    flutter doctor --android-licenses ;然后对提示回复y
    (如果licenses提示有问题的话,这一步必须要通过必须要执行,否则会导致后面程序无法执行)

    4、IDE添加插件


    Preferences-plugins添加Flutter和Dart插件

    5、如果没有安装gradle需要安装gradle

    安装连接 http://www.androiddevtools.cn/ 
    在Android开发工具中,可以下载gradle。然后在电脑Application目录中,找到Android Studio.app右键查看包文件,找到Content/gradle目录将刚刚下载解压后的gradle文件copy到该目录中。
    之后在终端输入 vi ~/.zshrc,打开后输入:
    GRADLE_HOME=/Applications/Android Studio.app/Contents/gradle/gradle-4.1;
    export GRADLE_HOME
    export PATH=PATH: :GRADLE_HOME/bin
    注意:配置中Android Studio.app中要加一个 转义,不然也会报错
    保存退出后输入:source ~/.zshrc 使配置生效
    然后在终端输入 gradle -version检查是否安装成功


    6、创建Flutter应用


    选择 File>New Flutter Project 。
    选择 Flutter application 作为 project 类型, 然后点击 Next。
    输入项目名称 (如 myapp),然后点击 Next。
    点击 Finish。
    等待Android Studio安装SDK并创建项目。

    mac连接手机成功后,点击debug,正常来说就能看到启动的应用程序了

    7、FAQ

    然而实际上并不一定能正常。。。

    1)如果运行失败提示,
    Finished with error: Please review your Gradle project setup in the android/ folder.
    可能性1,翻墙
    第一步:修改掉项目下的android目录下的build.gradle文件,把google() 和 jcenter()这两行去掉。改为阿里的链接。

    buildscript {
    repositories {
    //google()
    //jcenter()
    maven { url 'https://maven.aliyun.com/repository/google' }
    maven { url 'https://maven.aliyun.com/repository/jcenter' }
    maven { url 'http://maven.aliyun.com/nexus/content/groups/public' }
    }
    
    dependencies {
    classpath 'com.android.tools.build:gradle:3.1.2'
    }
    }


    第二步:修改Flutter SDK包下的flutter.gradle文件,这个目录要根据你的SDK存放的位置有所变化
    flutter.gradle文件中repositories中是google() 和 jcenter(),
    repositories{
    google()
    gcenter()
    }
    把google() 和 jcenter()这两行注释掉,改为阿里的链接。

    buildscript {
    repositories {
    //jcenter()
    //maven {
    // url 'https://dl.google.com/dl/android/maven2'
    //}
    maven{
    url 'https://maven.aliyun.com/repository/jcenter'
    }
    maven{
    url 'http://maven.aliyun.com/nexus/content/groups/public'
    }
    }
    dependencies {
    classpath 'com.android.tools.build:gradle:3.1.2'
    }
    }

    可能性2:如果更改后还是提示这个错误,检查下是否下载并成功安装gradle,没有的话重新安装下

    2)执行时,如果一直卡在Flutter Resolving dependencies...
    项目下的android目录下的build.gradle文件以及Flutter SDK包下的flutter.gradle文件
    classpath 'com.android.tools.build:gradle:3.0.1'
    最后的版本号和gradle的版本号要一致否则无法运行,大概在这个位置
    C:Program FilesAndroidAndroid Studiogradlem2repositorycomandroid oolsuildgradle

    3)
    Minimum supported Gradle version is 5.1.1. Current version is 4.10.2. If using the gradle wrapper, try editing the distributionUrl in /Users/wenfangzhu/AndroidStudioProjects/flutter_app/android/gradle/wrapper/gradle-wrapper.properties to gradle-5.1.1-all.zip
    这个提示是所指示的位置的配置不对,应该改成5.1.1

     ==================

    一个demo

    一、关于Dart语言

    在查看代码之前,首先我们来了解下Dart语言,Flutter在应用层使用Dart进行开发,而支撑它的是用C++开发的引擎

    Dart的设计综合借鉴了Java和JavaScript,在静态语法方面与Java相似,如类型定义、函数声明和泛型等,在动态特性上比如函数式特性、异步支持。

    • Dart是一种面向对象的语言
    • Dart是一种强类型语言
    • Dart有GC机制
    • Dart在运行之前会先解析代码
    • Dart中,Object类是所有对象的根基类
    • Dart的异步支持基于类似于JS的“Future返回结果”和“async 方法和 await 表达式”
    • Dart没有作用域关键字,如果标识符以_开头表示该方法或者属性为类私有
    • Dart是单线程的

    二、关于Widget

    Flutter Widget采用现代响应式框架构建,中心思想是用widget构建你的UI。

    Widget可以译为组件之类的,描述当前视图在当前的配置和状态时的展示形态,当Widget的状态发生改变时,UI会被重新构建,Flutter会对比前后变化的不同,以确定底层渲染树从一个状态转换到下一个状态所需的最小更改;这个思路和React有一定相似。

    基于以上,那么就有两个父类,无状态的StatelessWidget和有状态的StatefulWidget,这两个抽象类时直接集成自Widget类,日常使用中比较常用。

    • StatelessWidget用于不需要维护状态的场景,无状态组件不可变,通过build方法构建页面;

    • StatefulWidget用于有状态变化的场景,createState() 用于创建与Stateful widget对应的一个继承State类的子类,在State类中调用build方法构建页面

    三、代码:demo 

    // main.dart
    import 'package:flutter/material.dart'; //导入Material的UI组件库,来自谷歌,使展示更鲜明
    import 'home.dart';
    
    void main() => runApp(MyApp());// 程序的入口,调用runApp()启动程序, "=>"是单行方法的简写
    
    class MyApp extends StatelessWidget {
      // MyApp是一个继承于无状态statelessWidget的类
      @override
      Widget build(BuildContext context) {//调用build方法构建UI界面
        return MaterialApp( // 代表Material设计风格的应用,也是一个Widget,可定义应用名称,主题,首页
          title: 'Flutter Demo mfw',// 任务管理窗口所展示的应用名称
          theme: ThemeData( //应用的主题颜色
            primarySwatch: Colors.blue,
          ),
          home: Home(title: 'Flutter Demo Home Page'),//应用默认所要展示的界面
        );
      }
    }
    
    
    // home.dart:一个计数器,三个跳转路由
    class Home extends StatefulWidget {
      Home({Key key, this.title}) : super(key: key);
    
      final String title;
    
      @override
      _HomeState createState() => _HomeState();
    }
    
    
    class _HomeState extends State<Home> {
      int _counter = 0;
    
      void _incrementCounter() {// 监控按钮的增加数值方法
        setState(() {//通知Flutter框架有状态改变,Flutter框架收到通知后,会执行build方法重新构建界面
          _counter++;
        });
      }
    
      @override
      Widget build(BuildContext context) {
    
        return Scaffold(
          appBar: AppBar(
            title: Text(widget.title),
          ),
          body: Center(
    
            child: Column(
              mainAxisAlignment: MainAxisAlignment.center,
              children: <Widget>[
                Text(
                  'You have clicked the button this many times:',
                ),
                Text(
                  '$_counter',
                  style: Theme.of(context).textTheme.display1,
                ),
    
                FlatButton(
                  child: Text("open new case1"),
                  textColor: Colors.blue,
                  onPressed: (){
                    Navigator.push( context,
                        MaterialPageRoute(builder: (context){
                          return NewRoute();
                        }));
                  },
                ),
    
              FlatButton(
                child: Text("open new case2"),
               textColor: Colors.blue,
               onPressed: (){
                  Navigator.push( context,
                MaterialPageRoute(builder: (context){
                  return NewRoute1();
                }));
          },
        ),
    
              FlatButton(
              child: Text("open new case3"),
          textColor: Colors.blue,
          onPressed: (){
            Navigator.push( context,
                MaterialPageRoute(builder: (context){
                  return Route3();
                }));
          },
        )
    
              ],
            ),
          ),
          floatingActionButton: FloatingActionButton(
            onPressed: _incrementCounter,
            tooltip: 'Increment',
            child: Icon(Icons.add),
          ), 
        );
      }
    }
    

    一个小结

    一、测试期间可能遇到的问题

    1、Widget嵌套可能导致的问题

    2、由于单线程机制,Flutter本身不会导致crash,会卡顿

    3、UI溢出的报错,提示overflow

    4、由于状态管理有些笨重,动画效果的实现需要注意

    5、原生与flutter之间的互相跳转需要注意,与原生权限获取时是否有问题

    二、code方面的简单总结

    // 每个widget继承自StatelessWidget或者StatefuleWidegt
    // statelessWidget状态变化不大,statefulWidget分成两个,一个有build构建方法,一个继承自state类
    // 一个标准statelessWidget的Widget构建过程如下
    class  TestWidget extends StatelessWidegt{
    @override
    Widget build(BuildContext context){// build页面
    return 控件名(
    xxxx(child:内嵌其他控件
    ),
    .....
    )
    }
    };
    // 那么一个statefulWidget的构建过程
    class Test extends StatefulWideget{
    Route3({Key key}) : super(key: key);
    @override
    _TestState createState() => _TestState();  //新建state类
    }
    
    
    class _Route3State  extends State(Test){
    @override
    Widget build(BuildContext context)// 在state类里build页面
    ....
    }

    三、讲解问题记录

    1、flutter实现跨平台的原理是什么

    Flutter跨平台最核心的部分,是它的高性能渲染引擎(Flutter Engine)。Flutter不使用浏览器技术,也不使用Native的原生控件,它使用自己的渲染引擎来绘制widget。

    对于Android平台,Flutter引擎的C/C++代码是由NDK编译,在iOS平台,则是由LLVM编译,两个平台的Dart代码都是AOT编译为本地代码,Flutter应用程序使用本机指令集运行。

    Flutter正是是通过使用相同的渲染器、框架和一组widget,来同时构建iOS和Android应用,而无需维护两套独立的代码库。

    2、flutter的性能如何

    通过资料查询,原生在内存和CPU资源等性能方面,原生是要优于flutter的,flutter本身最大特点还是在于跨平台

    参考:

    flutter中文网

    flutter官网docs

  • 相关阅读:
    [java] 怎么去掉小数点后面不需要的0
    [SoapUI] 在SoapUI script里获取Response(Json格式)某个节点值
    nacos启动不停打印日志[com.alibaba.nacos.client.naming.updater] INFO com.alibaba.nacos.client.naming:192
    sppringcloud应用启动 访问gateway无法path无法路由到目标应用,404
    springcloud项目启动gateway报错org.springframework.cloud.gateway.config.GatewayAutoConfiguration required a bean of type 'org.springframework.http.codec.ServerCodecConfigurer' that could not be found
    nacos 01
    微服务spring-cloud day2
    springcloud本地启动指定profile后错误If you are using the git profile, you need to set a Git URI in your configuration.
    微服务spring-cloud day1
    金融云部署sofaboot应用指定了项目路径健康检查无法通过,windows格式/unix格式/mac格式的坑
  • 原文地址:https://www.cnblogs.com/zhuwf/p/12390100.html
Copyright © 2020-2023  润新知