Flutter实战记录

2018/09/29

Flutter

1. 概述

  1. Flutter实战

  2. Flutter Framework

  3. Flutter 主要内容

  4. Flutter_study

美团Flutter

Dart

2. Widget,都是其子类

2.1 基础

  1. 目录

2.2 主要包括控件

  • Container
  • Row
  • Column
  • Image: 从File, Assert, Mermory, Network获取图片;可设置alignment, centSlice, color, colorBlendMode, fit, filterQuality
  • Text: 单一格式的文本,Text.rich

  • Icon 可设置 color, icon, sementicLabel, size, textDirection
  • RaisedButton
  • Scafflod
  • Appbar

  • FlutterLogo
  • Placeholder

2.3 一个简单的APP需要的技术点

  1. 中文文档
  2. APP入口 runApp
  3. 应用结构
    • A 一切都是Widget子类
    • B MaterialApp 是Material库中提供的Flutter APP框架,通过它可以设置应用的名称、主题、语言、首页及路由列表等。MaterialApp也是一个widget。
    • C Scaffold 是Material库中提供的页面脚手架,它包含导航栏和Body以及FloatingActionButton(如果需要的化)。

  4. 导航——路由 PageRoute,
    • A类似于Activity,或ViewController

        Navigator.push( context,
           new MaterialPageRoute(builder: (context) {
                  return new NewRoute();
             }));
          },
         ),
      
    • B Navigator通过一个栈管理一个Route合集
    • C 注册路由表,处理跳转

        //注册路由表
      routes:{
       "new_page":(context)=>NewRoute(),
      } ,
       Navigator.pushNamed(context, "new_page"); 调用
      
    • D 无法动态修改tip内容,是不是可以类似Android一样添加Args 传递参数
  5. 包管理,通过一些依赖,可以使用DB Net等库
  6. Widget两个子类 StatefulWidget StatelessWidget
    • A State生命周期
      • 添加didiUpdateWidget, deactivate, dispose
      • initState —> didChangeDependencies —> build
      • 点击⚡️按钮热重载
      • —> reassemble —> didUpdateWidget —> build
      • —> reassemble debug —> deative —> dispose
    • B 响应式编程——状态管理

    • C 什么情况下需要创建有state的类
  7. UI布局
    • A 设想Android是怎么布局的
      • RelativeLayout{ImageView,RelativeLayout{
      • TextView, LinearLayout{Icon,Icon, Icon}, TextView}}
    • B Flutter 将每部分切割
      • 创建images,添加图片,在pubspec.yaml包含asset
      • 布局拆分,row column GridView 对齐填充,边框 等。
      • column

      • 如果要添加填充,边距,边框或背景色,请使用Container来设置(译者语:只有容器有这些属性)。
      • 使用Text的style属性来设置字体,颜色,粗细等。 列和行的属性允许您指定他们的子项如何垂直或水平对齐,以及应该占据多少空间
    • C 使用Scaffold是最容易的,提供了一个默认banner,背景颜色,并且具有添加drawer,snack bar和底部sheet的API。

    • D Row Column 可以理解为1行/列 有几个child 构成 ListView是列状布局
      • 对齐 对于行(Row)来说,主轴是水平方向,横轴垂直方向。对于列(Column)来说,主轴垂直方向,横轴水平方向。

  8. Cookbook

3. Dart

  1. 优点:
    • A 开发效率高
      • 在JIT 即时编译 模式下,速度与JS持平
      • 基于AOT模式发布包,生成高效ARM代码保证应用性能
    • B 高性能
    • C 快速内存分配
    • D 类型安全
    • E Dart团队随时对Flutter的支持
  2. 异步支持 Future 或者 Stream
  3. 既能进行服务端脚本、APP开发、web开发,
  4. 缺点
    • 性能没有比原生改善,Dart调用OpenGL,原生渲染
    • 无法支持热更
    • 在iOS普及上有极大的障碍
  5. 四大理由

4. 在原有Android工程中使用Flutter

  1. 原文

4.1 步骤

  1. 支持add-to-app
  2. 存在一个路径为 some/path/MyApp
    • $ cd some/path
    • $ flutter create -t model –org com.example my_flutter
    • 以上命令创建my_flutter模块,some/path/my_flutter
  3. 要求主APP支持java 1.8的编译
  4. 主APP对Flutter模块进行依赖
    • $ cd some/path/my_flutter
    • $ flutter build aar
    • 这个命令创建一个本地存储库,默认为release模式,如下

        build/host/outputs/repo
        └── com
        	 		 	└── example
       	 └── my_flutter
           	 └── flutter_release
                ├── 1.0
                │   ├── flutter_release-1.0.aar
                │   ├── flutter_release-1.0.aar.md5
                │   ├── flutter_release-1.0.aar.sha1
                │   ├── flutter_release-1.0.pom
                │   ├── flutter_release-1.0.pom.md5
                │   └── flutter_release-1.0.pom.sha1
                ├── maven-metadata.xml
                ├── maven-metadata.xml.md5
                └── maven-metadata.xml.sha1
      
    • 在MyApp/app/build.gradle下添加以下依赖

        // MyApp/app/build.gradle
      
        android {
          // ...
        }
      		
        repositories {
          maven {
            url 'some/path/my_flutter/build/host/outputs/repo'
          }
        }
      		
        dependencies {
            implementation project(':flutter')
          // ...
          releaseCompile ('com.example.my_flutter:flutter_release:1.0@aar') {
            transitive = true
          }
       }
      
  5. MyApp/settings.gradle添加

     // MyApp/settings.gradle
         include ':app'    // assumed existing content
         setBinding(new Binding([gradle:this]))     // new
         evaluate(new File(           
           settingsDir.parentFile,                       
           'my_flutter/.android/include_flutter.groovy'   
         ))                             
    
  6. 在Java代码中调用Flutter模块

    // MyApp/app/src/main/java/some/package/SomeActivity.java
     fab.setOnClickListener(new View.OnClickListener() {
      	 @Override
      	public void onClick(View view) {
     	FragmentTransaction tx = getSupportFragmentManager().beginTransaction();
     	tx.replace(R.id.someContainer, Flutter.createFragment("route1"));
     	tx.commit();
      	}
    });
    
  7. Flutter模块中添加

     import 'dart:ui';
     import 'package:flutter/material.dart';
    	
     void main() => runApp(_widgetForRoute(window.defaultRouteName));
     Widget _widgetForRoute(String route) {
       switch (route) {
         case 'route1':
           return SomeWidget(...);
         case 'route2':
           return SomeOtherWidget(...);
         default:
           return Center(
             child: Text('Unknown route: $route', textDirection: TextDirection.ltr),
           );
       }
     }
    
  8. 运行APP
  9. 热启/重载或debug dart 代码
    • 连接设备
    • $ cd some/path/my_flutter
    • $ flutter attach 连接手机

4.2 实践后的疑问与解答

  1. 通过依赖将my_flutter工程作为Android原工程的一个module添加到Android工程中,那这个flutter module修改,对应的my_flutter工程是否会一起改变——是的

  2. 修改flutter module的Android API,使用Androidx,并且用Jetpack相关库。

  3. Flutter的libs类中调用Java或者kotlin的接口

  4. Flutter生成的原Android工程使用的是Android support v7的库,我添加的Flutter module是Androidx,二者不能共存。AndroidX与Android support库不能共存报错

     Manifest merger failed : Attribute application@appComponentFactory value=(android.support.v4.app.CoreComponentFactory) from [com.android.support:support-compat:28.0.0] AndroidManifest.xml:22:18-91
      	is also present at [androidx.core:core:1.1.0-rc01] AndroidManifest.xml:24:18-86 value=(androidx.core.app.CoreComponentFactory).
      	Suggestion: add 'tools:replace="android:appComponentFactory"' to <application> element at AndroidManifest.xml:16:5-39:19 to override.
    
    ** app build.gradle 解决方案, 使用Android support 替换 Androidx**
    implementation 'com.android.support:appcompat-v7:28.0.0'
    implementation 'com.android.support.constraint:constraint-layout:1.1.3'
    implementation 'com.android.support:design:28.0.0'
    testImplementation 'junit:junit:4.12'
    androidTestImplementation 'com.android.support.test:runner:1.0.2'
    androidTestImplementation 'com.android.support.test.espresso:espresso-core:3.0.2'
  
    /*flutter build.gradle */
	  implementation 'com.android.support:support-v13:28.0.0'
	  implementation 'com.android.support:support-annotations:28.0.0'
	```
	
5. runapp 出错

_WidgetsFlutterBinding&BindingBase&GestureBinding&ServicesBinding&SchedulerBinding&PaintingBinding&SemanticsBinding&RendererBinding&WidgetsBinding.attachRootWidget


  解决办法

void main() => runApp(MyApp()); class MyApp extends StatelessWidget { // This widget is the root of your application. @override Widget build(BuildContext context) { return MaterialApp( title: ‘Home’, home: new MainPage(), ); }


6. Expanded与Container有什么区别

7. Flutter使用SharePreference与Android的有什么区别

8. 使用外部包
  1. `pubspec.yaml` (The pubspec.yaml file won’t change again.)添加一个依赖包`shared_preferences: ^0.4.2`,然后点击右上角`Packgets get`进行安装依赖包。或执行`flutter packages get`进行安装依赖包。
  2. `lib/main.dart`中`import 'package:shared_preferences/shared_preferences.dart';`

### 5. Flutter中序列化数据
1. [闲鱼的序列化方案](https://www.jiqizhixin.com/articles/2019-01-29-8)

#### 1. Json
1. `import 'dart:convert'; `内置convert库包含Json的编解码器.
2. `import 'package:json_annotation/json_annotation.dart';` 使用`json_serializable`自动化生成Json序列化模板。

#### 2. Protobuf <mac>
1. 安装`brew install protobuf`
2. 安装dart `brew tap dart-lang/dart;  brew install dart`
3. dart安装后,使用pub命令安装`protoc_plugin`:`pub global activate protoc_plugin`
4. 在`~/.bash_profile`添加环境变量`export "$PATH:$PWD/.pub-cache/bin"`,触发环境变量生效`source ~/.bash_profile`。
5. 将`.proto`文件编译成`.dart`文件:`protoc --dart_out=. pblog.proto`
	* 如果没有path,则使用`protoc --dart_out=. pblog.proto --plugin ~/.pub-cache/bin/protoc-gen-dart`
6. 在Flutter project中添加以下依赖`protobuf: ^0.13.4`

#### 存在的问题
1. json怎么转List<int>: `json.encode(body).codeUnits`
2. PB数据怎么转List<int>: `request.writeToBuffer()`


### 6. Flutter Dart完成项目
1. Dart interface怎么写 —— `abstract class`

2. 观察者模式

3. 单例模式

4. 线程 创建,同步 synchronized volatile

5. Tcp socket,`Datagram`包括socket的address,port以及数据。

    ```
    await Socket.connect(ip, port).then((socket) {
          LogUtils.w('HEHE', 'connect ok : ${socket.toString()}, ip : ${socket.address}, port : ${socket.remotePort}');
          this.socket = socket;
          // 创建成功后发送消息
          socketWrite();
    
          // 在protobuf中,与服务器交换的数据是模型的纯data,而在dart中data类型用List类型表示
          // 因此在本例中使用base64对收回数据进行编码后解码为List以供pb解析
          socket.listen((data) {
            readMessage(data);
          }, onError: errorHandler, onDone: doneHandler);
        });
    ```

    

    

6. DB创建,读写, 多线程处理

7. UI线程与工作线程交互

8. 设计模式,有没有MVP MVVM

9. java long —— `Int64代替`

   ![](https://raw.githubusercontent.com/rlq/image/master/flutter/f21_dart.png)

10. 异常捕获与抛出 `try {} on Exception catch (e){} `

11. 数据流,gzip压缩等

12. dart文件怎么才能不提供给外部import

13. Android原生的Build怎么调, package, application —— `flutter device_info`

14. 枚举enum,但不能放到class里呢; case; 枚举转为string—— `String enumTypeToString(EnumType type) => type.toString().split(".")[1];`

15. 随机数 —— `new Random()`

16. md5 —— `dart有md5的库`

17. instanceof —— `is`

18. Dart是否有重载— `没有`,继承 ,实现是怎么处理

19. TextUtils判空 —— `string.isEmpty`

20. ` Converting object to an encodable object failed: Instance of 'Int64'` 解决办法 `使用int类型`

21. Map 难道没有HashMap ; for循环

   ```java
   main() {
       Map<String, int> map = {
           'one': 1,
           'two': 2,
           'twelve': 12};
   
       void iterateMapEntry(key, value) {
         map[key] = value;
         print('$key:$value');//string interpolation in action
       }
       map.forEach(iterateMapEntry);
   }
  1. ByteBuffer怎么封装二进制数据

  2. flutter gzip, 多种压缩示例

     import 'dart:convert';
     import 'package:archive/archive.dart';
     main() {
       String data = 'use gzip';
       List<int> stringBytes = data.codeUnits;
       List<int> gzipBytes = new GZipEncoder().encode(stringBytes);
       /*但使用ZipDecoder解码有错
       [ERROR:flutter/lib/ui/ui_dart_state.cc(148)] ArchiveException: FormatException: Could not find End of Central Directory Record
       */
       Archive archive = new ZipDecoder().decodeBytes(buf);
       List<int> ungzipContent = new List();
       for (ArchiveFile file in archive) {
         if (file.isFile) {
           ungzipContent += file.content;
         }
       }
     }
         
     // 另一种办法
     void archive(List<int> dataBytes) {
         LogUtils.e('HEHE', 'source : ${data.length}, data : $dataBytes');
         List<int>  zipBytes = GZipCodec().encode(dataBytes);
         LogUtils.w('HEHE', 'zip : ${zipBytes.length}, data : $zipBytes');
         List<int>  unzipBytes = GZipCodec().decode(zipBytes);
         LogUtils.d('HEHE', 'ungizp : ${unzipBytes.length}, data : $unzipBytes');
     }
    
  3. async与sync的调用在同一个函数中

     [ERROR:flutter/lib/ui/ui_dart_state.cc(148)] Unhandled Exception: NoSuchMethodError: The getter 'timestamp' was called on null.`
    
  4. 生成二进制数据,FormatException: Invalid radix-10 number (at character 1)

  5. ByteData,ByteBuffer的使用

     ByteData bData = new ByteData(12 + rpc.length + payload.length);
     bData.setInt8(0, 10);
     bData.setInt8(1, 9);
     bData.setInt8(2, 7);
     bData.setInt8(3, 2);
     bData.setInt16(4, 200);
     bData.setInt16(8, 60);
    
  6. 如果有5个方法串联调用,第5个得使用async,那其他4个是不是都得用异步。改一个试试。—— 是的

  7. SharePerenfence没有默认值

    [ERROR:flutter/lib/ui/ui_dart_state.cc(148)] Unhandled Exception: Invalid argument(s): Illegal to set field token (2) of Request to value (null): not type String
    
  8. ConnectionTask 能否创建socket

  9. 判断网络连通性 connectivity

  10. Dart数据结构,python,Java

  11. Io

  12. StreamController与StreamBuilder 异步更新 UI

  13. `错误的内容

    Invalid plugin specification.

    Invalid “macos” plugin specification.`

    处理地址 :

    https://github.com/flutter/flutter/issues/52322

    https://www.gitmemory.com/issue/flutter/flutter/52322/597155433

    # flutter doctor -v
    Flutter (Channel master, 1.24.0-8.0.pre.252, on Mac OS X 10.15.6 19G2021 darwin-x64, locale zh-Hans-CN)
        • Flutter version 1.24.0-8.0.pre.252 at /Users/renliqin/Documents/github/flutter
        • Framework revision bf2c9dfc05 (23 hours ago), 2020-11-14 22:38:02 -0500
        • Engine revision 3e77d854a7
        • Dart version 2.12.0 (build 2.12.0-45.0.dev)
        • Pub download mirror https://pub.flutter-io.cn
        • Flutter download mirror https://storage.flutter-io.cn
        
    [!] Android toolchain - develop for Android devices (Android SDK version 29.0.2)
        • Android SDK at /Users/renliqin/Library/Android/sdk
        • Platform android-29, build-tools 29.0.2
        • ANDROID_HOME = /Users/renliqin/Library/Android/sdk
        • Java binary at: /Applications/Android Studio.app/Contents/jre/jdk/Contents/Home/bin/java
        • Java version OpenJDK Runtime Environment (build 1.8.0_242-release-1644-b3-6222593)
        ! Some Android licenses not accepted.  To resolve this, run: flutter doctor --android-licenses
        
    [!] Xcode - develop for iOS and macOS
        ✗ Xcode installation is incomplete; a full installation is necessary for iOS development.
          Download at: https://developer.apple.com/xcode/download/
          Or install Xcode via the App Store.
          Once installed, run:
            sudo xcode-select --switch /Applications/Xcode.app/Contents/Developer
            sudo xcodebuild -runFirstLaunch
        ! CocoaPods 1.8.3 out of date (1.9.0 is recommended).
            CocoaPods is used to retrieve the iOS and macOS platform side's plugin code that responds to your plugin usage on the Dart side.
            Without CocoaPods, plugins will not work on iOS or macOS.
            For more info, see https://flutter.dev/platform-plugins
          To upgrade see https://guides.cocoapods.org/using/getting-started.html#installation for instructions.
        
    [✓] Android Studio (version 4.0)
        • Android Studio at /Applications/Android Studio.app/Contents
        • Flutter plugin version 46.0.2
        • Dart plugin version 193.7361
        • Java version OpenJDK Runtime Environment (build 1.8.0_242-release-1644-b3-6222593)
        
    [✓] VS Code (version 1.50.0)
        • VS Code at /Applications/Visual Studio Code.app/Contents
        • Flutter extension version 3.15.0
        
    [✓] Connected device (1 available)
        • TAS AL00 (mobile) • JTK0219A24010807 • android-arm64 • Android 10 (API 29)
        
        
    

文内导航