Flutter进阶—Firebase数据库实例
来源:互联网 发布:路小雨知乎 编辑:程序博客网 时间:2024/05/29 04:40
如果需要使用Firebase实时数据库。首先我们需要为项目配置Firebase,具体配置方法可以在《Flutter实战一Flutter聊天应用(五)》查看,因为我们只需要使用Firebase数据库,所以pubspec.yaml
文件的内容需要修改一下。
name: talk_casuallydescription: A new flutter project.dependencies: flutter: sdk: flutter firebase_database: ^0.0.4
首先我们修改项目的main.dart
文件,代码如下。
import 'dart:async';import 'package:flutter/material.dart';import 'package:firebase_database/firebase_database.dart';import 'package:firebase_database/ui/firebase_animated_list.dart';void main() { runApp(new MyApp());}class MyApp extends StatelessWidget { @override Widget build(BuildContext context) { return new MaterialApp( title: 'Flutter数据库实例', home: new MyHomePage(), ); }}class MyHomePage extends StatefulWidget { @override _MyHomePageState createState() => new _MyHomePageState();}class _MyHomePageState extends State<MyHomePage> { @override Widget build(BuildContext context) { return new Scaffold( appBar: new AppBar( title: const Text('Flutter数据库实例'), ), ); }}
打开Firebase控制台,更改Firebase实时数据库的安全规则,选择“Database > 规则”,规则如下所示。
{ "rules": { "counter":{ ".read": true, ".write": true }, "messages":{ ".read": true, ".write": true } }}
现在我们需要使用DatabaseReference
连接到Firebase数据库,DatabaseReference
表示Firebase数据库中的特定位置,可用于读取或写入数据到该位置。
class _MyHomePageState extends State<MyHomePage> { //... final DatabaseReference _counterRef = FirebaseDatabase.instance.reference().child('counter'); final DatabaseReference _messagesRef = FirebaseDatabase.instance.reference().child('messages'); //...}
FirebaseDatabase
是访问Firebase数据库的入口点,我们可以通过调用FirebaseDatabase.instance
获取一个实例,要访问数据库中的位置并读取或写入数据,需要使用reference
。child
获取指定相对路径中的位置的DatabaseReference
,相对路径可以是简单的子key(例如“fred”)或更深的斜线分隔的路径(例如“fred/name/first”)。
我们先增加一个_counter
存储按钮点击次数。在默认情况下,用户的写入操作和缓存数据仅存储在内存中,并在用户重新启动应用程序时丢失。通过将启用持久性设置为true
,数据将持续存储在设备(磁盘)存储上,并在应用程序重新启动时再次可用(即使当时没有网络连接)。setPersistenceEnabled
能够开启数据库的持久性设置,必须在调用数据库引用方法之前设置此属性,并且每个应用程序只需要调用一次。如果操作成功,则Future将返回true
,如果持久性无法设置(可能是已经创建数据库引用),则返回false
。
class _MyHomePageState extends State<MyHomePage> { //... int _counter; //... @override void initState() { super.initState(); FirebaseDatabase.instance.setPersistenceEnabled(true); } //...}
现在我们的应用程序中,Firebase数据库客户端将缓存同步的数据,并跟踪用户在应用程序运行时发起的所有写入。当网络连接恢复时,它可以无缝地处理间歇性网络连接并重新发送写入操作。默认情况下,Firebase数据库客户端将使用高达10MB的磁盘空间来缓存数据。如果缓存增长超过此大小,客户端将开始删除尚未使用的数据。如果发现应用程序缓存数据太少或太多,可以使用setPersistenceCacheSizeBytes
来更改缓存大小。此属性必须在调用数据库引用方法之前设置,并且每个应用程序只需要调用一次。
class _MyHomePageState extends State<MyHomePage> { //... @override void initState() { super.initState(); FirebaseDatabase.instance.setPersistenceEnabled(true); FirebaseDatabase.instance.setPersistenceCacheSizeBytes(10000000); } //...}
如果操作成功,则Future将返回true
,如果该值无法设置,则为false
(可能已经创建数据库引用)。需要注意的是,指定的高速缓存大小只是一个近似值,并且磁盘上的大小有时会暂时超过它。该属性不支持小于1MB或大于100MB的缓存大小。
class _MyHomePageState extends State<MyHomePage> { //... @override void initState() { super.initState(); FirebaseDatabase.instance.setPersistenceEnabled(true); FirebaseDatabase.instance.setPersistenceCacheSizeBytes(10000000); _counterRef.keepSynced(true); } //...}
通过在某个位置调用keepSynced(true)
,即使没有为该位置附加任何监听器,该位置的数据将自动下载并保持同步。另外,当一个位置保持同步时,它不会被从持久磁盘缓存中逐出。
现在我们增加两个StreamSubscription
类型的变量,StreamSubscription
表示来自Stream
的事件的订阅。订阅将提供事件给侦听器,并保存用于处理事件的回调。订阅也可以用于取消订阅事件,或者临时暂停Stream
中的事件。Stream
是异步数据事件的来源,Stream
提供了一种接收一系列事件的方式。每个Event
都是一个数据事件,也称为流的元素,或者一个错误事件。当流已经发出其所有事件时,一个“完成”事件将通知侦听器已到达结束。我们可以监听流,使其开始生成事件,并设置接收事件的侦听器。当我们侦听时,将收到一个StreamSubscription
对象,该对象是提供事件的活动对象,可以用于停止再次监听,或临时暂停订阅的事件。
class _MyHomePageState extends State<MyHomePage> { //... StreamSubscription<Event> _counterSubscription; StreamSubscription<Event> _messagesSubscription; //...}
现在需要在应用程序启动时读取按钮被点击的次数。onValue
表示当该位置的数据更新时触发。Event
里封装了DataSnapshot
,也可能是其以前的兄弟的key,通常用于命令快照(即返回一个DataSnapshot
)。DataSnapshot
包含来自Firebase数据库位置的数据,每当我们读取Firebase数据时,将收到一个DataSnapshot
。DataSnapshot
的value
属性以本机类型返回此数据快照的内容。
class _MyHomePageState extends State<MyHomePage> { //... @override void initState() { //... _counterSubscription = _counterRef.onValue.listen((Event event) { setState(() { _counter = event.snapshot.value ?? 0; }); }); } //...}
上面代码中的双问号操作符意思是取所赋值??左边的,如果左边为null,取所赋值??右边的。应用程序在启动时还应该获取消息列表,还可以打印在控制台上。DatabaseReference
的limitToLast
方法会创建一个有限制的查询并将其锚定到窗口的末尾。onChildAdded
表示在子数据加入时调用。当我们使用Stream.listen
在Stream
上侦听时,会返回一个StreamSubscription
对象。
class _MyHomePageState extends State<MyHomePage> { //... @override void initState() { //... _messagesSubscription = _messagesRef.limitToLast(10).onChildAdded.listen((Event event) { print('子数据增加了: ${event.snapshot.value}'); }); } //...}
在资源使用完之后及时关闭是一个良好的习惯,StreamSubscription
的cancel
方法用于取消订阅,在此调用之后,订阅不再接收事件。流可能需要关闭事件源,并在订阅取消后进行清理。
class _MyHomePageState extends State<MyHomePage> { //... @override void dispose() { super.dispose(); _messagesSubscription.cancel(); _counterSubscription.cancel(); } //...}
修改build
的内容,使我们可以看到查看按钮被点击了多少次。
class _MyHomePageState extends State<MyHomePage> { //... @override Widget build(BuildContext context) { return new Scaffold( appBar: new AppBar( title: const Text('Flutter数据库实例'), ), body: new Column( children: <Widget>[ new Flexible( child: new Center( child: new Text( '按钮点击 $_counter 次,\n\n该统计包括所有的终端!', ), ), ), ], ), ); } //...}
再增加一个_anchorToBottom
变量,控制显示消息列表的样式。
class _MyHomePageState extends State<MyHomePage> { //... bool _anchorToBottom = false; //...}
修改build
的内容,增加一个可选项,按钮如何显示消息列表。
class _MyHomePageState extends State<MyHomePage> { //... @override Widget build(BuildContext context) { return new Scaffold( //... body: new Column( children: <Widget>[ //... new ListTile( leading: new Checkbox( onChanged: (bool value) { setState(() { _anchorToBottom = value; }); }, value: _anchorToBottom, ), title: const Text('锚点到底部'), ), ], ), ); } //...}
现在可以使用FirebaseAnimatedList
控件把消息列表显示出来,FirebaseAnimatedList
是绑定到查询的AnimatedList
控件。
class _MyHomePageState extends State<MyHomePage> { //... @override Widget build(BuildContext context) { return new Scaffold( //... body: new Column( children: <Widget>[ //... new Flexible( child: new FirebaseAnimatedList( key: new ValueKey<bool>(_anchorToBottom), query: _messagesRef, reverse: _anchorToBottom, sort: _anchorToBottom ? (DataSnapshot a, DataSnapshot b) => b.key.compareTo(a.key) : null, itemBuilder: (BuildContext context, DataSnapshot snapshot, Animation<double> animation) { return new SizeTransition( sizeFactor: animation, child: new Text(snapshot.value.toString()), ); }, ), ) ], ), ); } //...}
在FirebaseAnimatedList
控件中,key
属性控制一个控件如何替换树中另一个控件,query
属性设置用于填充动画列表的Firebase查询,reverse
属性设置滚动视图是否在阅读方向滚动,sort
属性设置用于在排序列表时比较快照的可选功能,itemBuilder
属性根据需要调用来构建列表项控件。
我们需要编写一个提交事件,用于将数据上传到数据库。DatabaseReference
的once
方法侦听单个值事件,然后停止侦听。DatabaseReference
的set
方法将值写入具有指定优先级的位置(如果适用),这将覆盖此位置的所有数据。允许写入的数据类型有String
、boolean
、int
、double
、Map
和List
,写入的效果将立即可见,相应的事件将被触发。如果传递新值为null
,表示此位置的所有数据将被删除。
class _MyHomePageState extends State<MyHomePage> { //... String _kTestKey = 'Hello'; String _kTestValue = 'world!'; //... Future<Null> _increment() async { final DataSnapshot snapshot = await _counterRef.once(); setState(() { _counter = (snapshot.value ?? 0) + 1; }); _counterRef.set(_counter); _messagesRef.push().set(<String, String>{_kTestKey: '$_kTestValue $_counter'}); } //...}
DatabaseReference
的push
方法使用唯一key生成新的子位置并返回一个DatabaseReference
。当Firebase数据库位置的子位置是一个列表时,这个方法非常有用。由childByAutoId
生成的唯一key以客户端生成的时间戳为前缀,以便生成的列表将按时间顺序排序。
最后我们修改build
的内容,增加一个浮动按钮,并将上面编写的事件作为其点击事件。
class _MyHomePageState extends State<MyHomePage> { //... @override Widget build(BuildContext context) { return new Scaffold( appBar: new AppBar( title: const Text('Flutter数据库实例'), ), body: new Column( //... ), floatingActionButton: new FloatingActionButton( onPressed: _increment, tooltip: '增加', child: new Icon(Icons.add), ), ); } //...}
启动应用程序,点击按钮三次,控制台与终端的显示如下:
数据库内容显示如下:
- Flutter进阶—Firebase数据库实例
- Flutter进阶—构建布局实例
- Flutter进阶—简单平台插件实例
- Flutter进阶—铅刀一割
- Flutter基础—第一个Flutter实例
- Flutter进阶—解析动画
- Flutter进阶—平台插件
- Flutter基础—应用实例
- Flutter进阶—读取与写入文件
- Flutter进阶—质感设计之进度条
- Flutter进阶—质感设计之卡片
- Flutter进阶—使用自定义字体
- Flutter进阶—布局方法演示
- Flutter进阶—布局一个控件
- Flutter进阶—垂直和水平布局
- Flutter进阶—通用布局控件
- Flutter进阶—创建有状态控件
- Flutter进阶—路由和导航
- ubunut,已经安装nginx,开启SSL模块
- verilog parameter localparam define使用
- L2-011 玩转二叉树
- 移动端touch事件---利用bootstrap实现轮播图手指左右滑动事件
- Java中 while与do--while 区别
- Flutter进阶—Firebase数据库实例
- JDK8.0 流stream 基本操作
- 如何给程序员做绩效考核
- AndroidStudio2.2NDK CMakeLists.txt配置新的.cpp
- java读属性文件实例
- C语言
- 百度Map
- CRC校验
- 【转载】CentOS下用pyenv 和 virtualenv 搭建单机多版本python 虚拟开发环境