Flutter云数据库缓存插件firestore_cache的使用

发布于 1周前 作者 sinazl 来自 Flutter

Flutter云数据库缓存插件firestore_cache的使用

插件介绍

firestore_cache 是一个用于Flutter应用程序的插件,它允许从Firestore中获取文档时优先读取缓存数据,然后再从服务器获取最新数据。这对于减少网络请求次数、提高应用响应速度非常有用。该插件主要用于那些使用cloud_firestore插件中的DocumentReference.get()Query.get()方法的应用程序。

插件特性

  • 优先读取缓存:在每次查询时,先尝试从本地缓存中读取数据。
  • 基于时间戳更新策略:通过比较缓存中的时间戳字段来决定是否需要从服务器拉取新数据。
  • 易于集成:与现有的Firestore操作无缝结合。

快速开始

添加依赖

首先,在项目的pubspec.yaml文件中添加firestore_cache作为依赖:

dependencies:
  firestore_cache: ^2.15.3

然后运行 flutter pub get 来安装此插件。

使用示例

创建Firestore文档

确保你在Firestore中创建了一个包含时间戳字段(如updatedAt)的文档。例如:

/status/status
    - updatedAt: Timestamp

编写代码

下面是一个完整的Flutter项目示例,展示了如何使用firestore_cache来获取单个文档以及文档集合,并显示它们是否来自缓存。

import 'package:cloud_firestore/cloud_firestore.dart';
import 'package:firebase_core/firebase_core.dart';
import 'package:firestore_cache/firestore_cache.dart';
import 'package:flutter/material.dart';

void main() async {
  WidgetsFlutterBinding.ensureInitialized();
  await Firebase.initializeApp();
  runApp(const MyApp());
}

class MyApp extends StatelessWidget {
  const MyApp({super.key});

  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      title: 'Firestore Cache Demo',
      theme: ThemeData(
        primarySwatch: Colors.blue,
        visualDensity: VisualDensity.adaptivePlatformDensity,
      ),
      home: const MyHomePage(),
    );
  }
}

class MyHomePage extends StatefulWidget {
  const MyHomePage({super.key});

  @override
  MyHomePageState createState() => MyHomePageState();
}

class MyHomePageState extends State<MyHomePage> {
  final _firestore = FirebaseFirestore.instance;
  late Future<DocumentSnapshot<Map<String, dynamic>>> _futureDoc;
  late Future<QuerySnapshot<Map<String, dynamic>>> _futureSnapshot;

  @override
  void initState() {
    super.initState();
    _futureDoc = _getDoc();
    _futureSnapshot = _getDocs();
  }

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(title: const Text('Firestore Cache Demo')),
      body: Center(
        child: Column(
          mainAxisAlignment: MainAxisAlignment.center,
          crossAxisAlignment: CrossAxisAlignment.center,
          children: <Widget>[
            const Text('Get single document'),
            _buildDoc(),
            const Divider(),
            const Text('Get collection of documents'),
            _buildDocs(),
          ],
        ),
      ),
    );
  }

  Widget _buildDoc() {
    return FutureBuilder<DocumentSnapshot>(
      future: _futureDoc,
      builder: (context, snapshot) {
        if (snapshot.hasError) {
          return Text('${snapshot.error}');
        } else if (snapshot.hasData) {
          final doc = snapshot.data!;
          final data = doc.data() as Map?;

          return Text(
            '${data!['userId']} isFromCache: ${doc.metadata.isFromCache}',
          );
        }

        return const CircularProgressIndicator();
      },
    );
  }

  Widget _buildDocs() {
    return FutureBuilder<QuerySnapshot>(
      future: _futureSnapshot,
      builder: (context, snapshot) {
        if (snapshot.hasError) {
          return Text('${snapshot.error}');
        } else if (snapshot.hasData) {
          final docs = snapshot.data?.docs;
          return Expanded(
            child: ListView(
              children: docs!.map((DocumentSnapshot doc) {
                final data = doc.data() as Map?;
                return Text(
                  '${data!['postId']} isFromCache: ${doc.metadata.isFromCache}',
                  textAlign: TextAlign.center,
                );
              }).toList(),
            ),
          );
        }

        return const CircularProgressIndicator();
      },
    );
  }

  Future<DocumentSnapshot<Map<String, dynamic>>> _getDoc() async {
    final docRef = _firestore.doc('users/user');
    final doc = await FirestoreCache.getDocument(docRef);

    return doc;
  }

  Future<QuerySnapshot<Map<String, dynamic>>> _getDocs() async {
    const cacheField = 'updatedAt';
    final cacheDocRef = _firestore.doc('status/status');
    final query = _firestore.collection('posts');
    final snapshot = await FirestoreCache.getDocuments(
      query: query,
      cacheDocRef: cacheDocRef,
      firestoreCacheField: cacheField,
    );

    return snapshot;
  }
}

在这个例子中:

  • _getDoc() 方法用来获取单个用户文档,并检查它是从缓存还是从服务器获取。
  • _getDocs() 方法用来获取帖子列表,并同样地检查每个文档是否来自缓存。

请注意,为了使缓存机制生效,你需要确保Firestore中的每个相关文档都有一个时间戳字段(例如updatedAt),并且在更新这些文档时正确设置这个字段。


希望以上信息对你有所帮助!如果你有任何问题或需要进一步的帮助,请随时提问。


更多关于Flutter云数据库缓存插件firestore_cache的使用的实战系列教程也可以访问 https://www.itying.com/category-92-b0.html

1 回复

更多关于Flutter云数据库缓存插件firestore_cache的使用的实战系列教程也可以访问 https://www.itying.com/category-92-b0.html


当然,下面是一个关于如何在Flutter项目中使用firestore_cache插件来缓存Firestore数据的示例代码。firestore_cache是一个Flutter插件,用于缓存Firebase Firestore的数据,以提高应用的性能和响应速度。

首先,确保你已经在pubspec.yaml文件中添加了firestore_cache依赖:

dependencies:
  flutter:
    sdk: flutter
  cloud_firestore: ^x.y.z  # 确保使用兼容的版本
  firestore_cache: ^a.b.c  # 使用最新版本

然后运行flutter pub get来安装依赖。

接下来,我们编写一个示例代码,展示如何使用firestore_cache来缓存Firestore的数据。

示例代码

import 'package:flutter/material.dart';
import 'package:cloud_firestore/cloud_firestore.dart';
import 'package:firestore_cache/firestore_cache.dart';

void main() {
  runApp(MyApp());
}

class MyApp extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      title: 'Firestore Cache Example',
      theme: ThemeData(
        primarySwatch: Colors.blue,
      ),
      home: MyHomePage(),
    );
  }
}

class MyHomePage extends StatefulWidget {
  @override
  _MyHomePageState createState() => _MyHomePageState();
}

class _MyHomePageState extends State<MyHomePage> {
  final FirestoreCache firestoreCache = FirestoreCache();
  CollectionReference<Map<String, dynamic>> usersRef = FirebaseFirestore.instance.collection('users');

  @override
  void initState() {
    super.initState();
    // Initialize the cache
    firestoreCache.initialize(
      collection: 'users',
      duration: Duration(minutes: 10),  // Cache duration
      onSnapshot: (snapshot) {
        // Handle cached snapshot, e.g., update UI
        print('Cached snapshot: ${snapshot.docs}');
      },
    );
  }

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: Text('Firestore Cache Example'),
      ),
      body: FutureBuilder<QuerySnapshot<Map<String, dynamic>>>(
        future: fetchUsersWithCache(),
        builder: (context, snapshot) {
          if (snapshot.connectionState == ConnectionState.waiting) {
            return Center(child: CircularProgressIndicator());
          } else if (snapshot.hasError) {
            return Center(child: Text('Error: ${snapshot.error}'));
          } else {
            return ListView.builder(
              itemCount: snapshot.data?.docs.length,
              itemBuilder: (context, index) {
                Map<String, dynamic> user = snapshot.data?.docs[index].data() as Map<String, dynamic>;
                return ListTile(
                  title: Text(user['name'] as String),
                  subtitle: Text(user['email'] as String),
                );
              },
            );
          }
        },
      ),
    );
  }

  Future<QuerySnapshot<Map<String, dynamic>>> fetchUsersWithCache() async {
    // Attempt to fetch data from cache first
    QuerySnapshot<Map<String, dynamic>>? cachedSnapshot = await firestoreCache.getSnapshot();
    if (cachedSnapshot != null) {
      return cachedSnapshot;
    }

    // If cache is empty or expired, fetch from Firestore
    QuerySnapshot<Map<String, dynamic>> snapshot = await usersRef.get();
    // Update cache with new data
    await firestoreCache.updateCache(snapshot);
    return snapshot;
  }
}

说明

  1. 依赖安装:首先,在pubspec.yaml中添加cloud_firestorefirestore_cache依赖。

  2. 初始化缓存:在initState方法中,使用firestoreCache.initialize方法初始化缓存。你需要指定要缓存的集合名称、缓存持续时间以及缓存快照更新时的回调函数。

  3. 获取数据:在fetchUsersWithCache方法中,首先尝试从缓存中获取数据。如果缓存中有数据,则直接返回缓存的数据;否则,从Firestore获取数据并更新缓存。

  4. UI展示:使用FutureBuilder来异步获取数据并展示在UI上。

这只是一个简单的示例,展示了如何使用firestore_cache插件来缓存Firestore数据。你可以根据实际需求进一步扩展和优化代码。

回到顶部