扣丁书屋

Flutter 入门笔记(Part 8) 数据持久化与调原生方法

2 . 数据持久化

  • 由于 Flutter 仅接管了渲染层,真正涉及到存储等操作系统底层行为时,还需要依托于原生 Android、iOS.
  • 三种数据持久化方法,即文件、SharedPreferences 与数据库
  • Flutter 提供了两种文件存储的目录,即临时(Temporary)目录与文档(Documents)目录:

2.1 文件

需要引入: path_provider: ^1.6.4

//创建文件目录
Future<File> get _localFile async {
  final directory = await getApplicationDocumentsDirectory();
  final path = directory.path;
  return File('$path/content.txt');
}
//将字符串写入文件
Future<File> writeContent(String content) async {
  final file = await _localFile;
  return file.writeAsString(content);
}
//从文件读出字符串
Future<String> readContent() async {
  try {
    final file = await _localFile;
    String contents = await file.readAsString();
    return contents;
  } catch (e) {
    return "";
  }
}

2.2 SharedPreferences

需要引入: shared_preferences: ^0.5.6+2

//读取SharedPreferences中key为counter的值
Future<int>_loadCounter() async {
  SharedPreferences prefs = await SharedPreferences.getInstance();
  int  counter = (prefs.getInt('counter') ?? 0);
  return counter;
}

//递增写入SharedPreferences中key为counter的值
Future<void>_incrementCounter() async {
  SharedPreferences prefs = await SharedPreferences.getInstance();
    int counter = (prefs.getInt('counter') ?? 0) + 1;
    prefs.setInt('counter', counter);
}

2.3 数据库

需要引入: sqflite: ^1.2.1

dbDemo() async {
    final Future<Database> database = openDatabase(
      //join是拼接路径分隔符
      join(await getDatabasesPath(), 'student_database.db'),
      onCreate: (db, version) => db.execute(
          "CREATE TABLE students(id TEXT PRIMARY KEY,name TEXT,score INTEGER)"),
      onUpgrade: (db, oldVersion, newVersion) {
        //dosth for 升级
      },
      version: 1,
    );

    Future<void> insertStudent(Student std) async {
      final Database db = await database;
      await db.insert(
        'students',
        std.toJson(),
        //插入冲突策略,新的替换旧的
        conflictAlgorithm: ConflictAlgorithm.replace,
      );
    }

    //插入3个
    await insertStudent(student1);
    await insertStudent(student2);
    await insertStudent(student3);

    Future<List<Student>> students() async {
      final Database db = await database;
      final List<Map<String, dynamic>> maps = await db.query('students');
      return List.generate(maps.length, (i) => Student.fromJson(maps[i]));
    }

    ////读取出数据库中插入的Student对象集合
    students().then((list) => list.forEach((s) => print(s.name)));
    //释放数据库资源
    final Database db = await database;
    db.close();
  }

3 . Flutter调原生

  • 用AS单独打开Flutter项目中的Android工程,写代码,每次写完代码rebuild一下.然后想让Flutter代码能调到Android这边的代码,得重新运行.
  • 如果AS run窗口不展示任何消息,可以使用 命令flutter run lib/native/invoke_method.dart执行dart,然后看错误消息.
  • Flutter发起方法调用请求开始,请求经由唯一标识符指定的方法通道到达原生代码宿主,而原生代码宿主则通过注册对应方法实现,响应并处理调用请求.最后将执行结果通过消息通道,回传至Flutter.
  • 方法通道是非线程安全的,需要在UI线程(Android或iOS的主线程)回调.
  • 数据持久化,推送,摄像头,蓝牙等,都需要平台支持
  • 轻量级解决方案: 方法通道机制 Method Channel
  • 调用示例:
class _MyHomePageState extends State<MyHomePage> {
  //声明MethodChannel
  static const platform = MethodChannel('com.xfhy.basic_ui/util');


  handleButtonClick() async {
    bool result;
    //捕获  万一失败了呢
    try {
      //异步等待,可能很耗时  等待结果
      result = await platform.invokeMethod('isEmpty', "have data");
    } catch (e) {
      result = false;
    }
    print('result : $result');
  }

}

//Android代码
import androidx.annotation.NonNull
import io.flutter.embedding.android.FlutterActivity
import io.flutter.embedding.engine.FlutterEngine
import io.flutter.plugin.common.MethodChannel
import io.flutter.plugins.GeneratedPluginRegistrant

class MainActivity : FlutterActivity() {

    override fun configureFlutterEngine(@NonNull flutterEngine: FlutterEngine) {
        GeneratedPluginRegistrant.registerWith(flutterEngine)

        //参考: https://flutter.dev/docs/development/platform-integration/platform-channels

        MethodChannel(flutterEngine.dartExecutor.binaryMessenger, "com.xfhy.basic_ui/util").setMethodCallHandler { call, result ->
            //判断方法名是否支持
            if (call.method == "isEmpty") {
                val arguments = call.arguments
                result.success(StringUtil.isEmpty(arguments as? String))
                print("success")
            } else {
                //方法名暂不支持
                result.notImplemented()
                print("fail")
            }
        }
    }
}

  • Android或者iOS的数据会被序列化成一段二进制格式的数据在通道中传输,当该数据传递到Flutter后,又会被反序列化成Dart语言中的类型.

https://mp.weixin.qq.com/s/cD6mOTKxvcG1_oUtFFYxmA

最多阅读

如何有效定位Flutter内存问题? 9月以前  |  10183次阅读
Flutter的手势GestureDetector分析详解 2年以前  |  5108次阅读
Flutter插件详解及其发布插件 2年以前  |  4192次阅读
在Flutter中添加资源和图片 2年以前  |  3807次阅读
发布Flutter开发的iOS程序 2年以前  |  3033次阅读
Flutter 状态管理指南之 Provider 2年以前  |  2781次阅读
在Flutter中发起HTTP网络请求 2年以前  |  2685次阅读
Flutter for Web详细介绍 2年以前  |  2639次阅读
使用Inspector检查用户界面 2年以前  |  2605次阅读
Flutter Widget框架概述 2年以前  |  2357次阅读
Flutter框架概览 2年以前  |  2200次阅读
JSON和序列化 2年以前  |  2197次阅读
为Flutter应用程序添加交互 2年以前  |  2175次阅读
Flutter路由详解 2年以前  |  2168次阅读
处理文本输入 2年以前  |  2042次阅读
使用自定义字体 2年以前  |  2033次阅读
编写国际化Flutter App 2年以前  |  1992次阅读
推荐5个Flutter重磅开源项目! 1年以前  |  1987次阅读

手机扫码阅读