【问题标题】:Offline Persistence using API REST Firebase and Flutter使用 API REST Firebase 和 Flutter 实现离线持久化
【发布时间】:2020-11-15 07:05:33
【问题描述】:

我正在开发一个 Agro 应用程序,当我观看 Firebase 宣传视频时,我真的很喜欢他们描述应用程序的方式,即使没有互联网(离线持久性)也是如此。

为了开发我使用过的应用程序:

  • 颤动
  • Firebase API REST(http 插件)
  • 向 API 发出请求的提供者
  • BLOC 模式

我的应用程序已经基本完成了,但是我注意到当没有互联网时会出现错误:

SocketException:主机查找失败:'node1.bitcoiin.com'(操作系统错误:没有与主机名关联的地址,errno = 7)

Medium 上的@IshwarChandra 澄清了我:

当您在 Firebase 中使用离线持久性时,请勿使用事务 或等待回复。

对吗?真的可以在不使用等待的情况下从 Firebase 检索数据吗?我问这个是因为我在某些情况下实现了 BLOC 模式,从而从用户界面中删除了等待。然而,它背后总是调用一个等待加载数据的 Provider。

另一方面,StackOverFlow 的一位开发人员向我表示,离线持久性管理只能使用 Flutter SDK 和

这是不可能的(或者需要太多的编程)来实现 就像我一直在使用它一样,它与 REST API 一起使用。

这个说法正确吗?如果是这样,我有以下疑问:

  1. 是否有文档或提示可以让我轻松地将 http REST Firebase API 请求(我主要在 Provider 中)迁移到 Flutter 中的 Firebase SDK?

  2. 我可以保留我正在使用的 BLOC 和 PROVIDER 的架构吗?

  3. 在进行更改之前还有其他提示吗?

我的 Providers 上的示例代码供您参考:

import 'dart:convert';
import 'package:aplians_fish/src/preferencias_usuario/preferencias_usuario.dart';
import 'package:http/http.dart' as http;
import 'package:aplians_fish/src/models/alimentar_model.dart';

class AlimentarProvider {

  final String _url ='https://apliansdb.firebaseio.com';

  final _prefs = new PreferenciasUsuario();


// ==========================================================
// ======================== CREATE ==========================
// ==========================================================

  Future<bool> crearAlimentar(AlimentarModel alimentar, String idEmpresa, String idEstanque) async {


    final url ='$_url/empresas/$idEmpresa/estanques/$idEstanque/loteActual/alimentacion.json?auth=${_prefs.token}';
   
    final resp = await http.post(url, body: alimentarModelToJson(alimentar));
    final decodedData = json.decode(resp.body); // Da la respuesta, sea un cargue o un error
    print(decodedData);
    return true;
   
  }

// ==========================================================
// ================== READ  =====================
// ==========================================================

  Future<List<AlimentarModel>> cargarAlimentar(String idEmpresa, String idEstanque) async {

    final url ='$_url/empresas/$idEmpresa/estanques/$idEstanque/loteActual/alimentacion.json?auth=${_prefs.token}';
    final resp = await http.get(url);

    final Map<String, dynamic> decodedData = json.decode(resp.body);
    final List<AlimentarModel> alimentar = new List();

    if (decodedData == null) return [];
    if (decodedData['error'] != null) return [];

    decodedData.forEach((id, alim){
      final temp = AlimentarModel.fromJson(alim);
      temp.idAlimentar = id;

      alimentar.add(temp);
      
    });

    return alimentar;

  }

// ==========================================================
// =========================== UPDATE =======================
// ==========================================================

  Future<bool> editarAlimentar(String idEmpresa, String idEstanque, AlimentarModel alimentar) async {
    
    final url = '$_url/empresas/$idEmpresa/estanques/$idEstanque/loteActual/alimentacion/${alimentar.idAlimentar}.json?auth=${_prefs.token}';

    final resp = await http.put(url, body: alimentarModelToJson(alimentar));
    final decodedData = json.decode(resp.body);
    print(decodedData);
    return true;

  }

// ==========================================================
// ================== DELETE =======================
// ==========================================================


  Future<bool> borrarAlimentar(String idEmpresa, String idEstanque, String id) async {
    final url = '$_url/empresas/$idEmpresa/estanques/$idEstanque/loteActual/alimentacion/$id.json?auth=${_prefs.token}';
    final resp = await http.delete(url);
    print(json.decode(resp.body));
    return true;
  }


}

而且,这就是我使用 BLOC 的方式:

import 'package:rxdart/rxdart.dart';
import 'package:aplians_fish/src/models/alimentar_model.dart';
import 'package:aplians_fish/src/providers/alimentar_provider.dart';


class AlimentarBloc {

  final _alimentarController = new BehaviorSubject<List<AlimentarModel>>();
  final _cargandoController = new BehaviorSubject<bool>();
  final _alimentarProvider = new AlimentarProvider();

  Stream <List<AlimentarModel>>        get alimentarStream    => _alimentarController.stream;
  Stream <bool>                        get cargando           => _cargandoController.stream;


  Future<List<AlimentarModel>> cargarAlimentar(String idEmpresa, String idEstanque) async {
    final alimentar = await _alimentarProvider.cargarAlimentar(idEmpresa, idEstanque);
    // ahora hay que insertar estos productos al stream...
    _alimentarController.sink.add(alimentar);
    return alimentar;
  }

   Future<bool> crearAlimentar(AlimentarModel alimentar, String idEmpresa, String idEstanque) async {
    
    _cargandoController.sink.add(true);
    await _alimentarProvider.crearAlimentar(alimentar, idEmpresa, idEstanque);
    _cargandoController.sink.add(false); //este es útil para bloquear botones cuando se esté cargando
    // esto se hace para notificar que está cargando el producto y de esa forma espere
    return true;

  }


  void editarAlimentar(String idEmpresa, String idEstanque, AlimentarModel alimentar) async {
    
    _cargandoController.sink.add(true);
    await _alimentarProvider.editarAlimentar(idEmpresa, idEstanque, alimentar);
    _cargandoController.sink.add(false);
    // esto se hace para notificar que está cargando el producto y de esa forma espere

  }


  Future<bool> borrarAlimentar(String idEmpresa, String idEstanque, String id) async {
    
    // _cargandoController.sink.add(true);
    await _alimentarProvider.borrarAlimentar(idEmpresa, idEstanque, id);
    // _cargandoController.sink.add(false);
    // no se requieren los controllers porque para la persona al desplazar, siente que ya se borró
    return true;

  }

  dispose() {
    _alimentarController?.close();
    _cargandoController?.close();
  }

}

【问题讨论】:

    标签: firebase flutter dart firebase-realtime-database sdk


    【解决方案1】:

    您似乎正在通过 Firebase 实时数据库的 REST API 获取数据。 Firebase SDK 实现了客户端缓存,但由于您没有使用 SDK,因此您也没有使用 SDK 中的缓存。

    要了解如何使用 SDK 从 Firebase 读取数据,我建议您阅读(例如)Androidexample in the Flutter library 的 Firebase 文档。在这些之间,您应该能够找出映射。如果您的特定代码有问题,请针对该问题发布一个新问题。

    使用 BLoC 与是否使用 Firebase 无关,因此只要将与数据库交互的代码从使用 REST API 映射到使用 Firebase SDK,就可以继续使用它们。

    【讨论】:

    • 谢谢。最后一个问题。为了支持离线持久化,如果我改用 SDK……我真的需要停止使用 BLOC 中的等待吗?
    • Firebase SDK 还从服务器异步检索数据,因此(取决于您的实现方式)您可能仍在等待结果或收听流。
    • Android 文档参考包括 Java 和 Kotlin 示例,但我使用的是 Flutter / DART。我该怎么做?
    • 在我的回答中,我建议阅读 Android 文档以了解该过程,然后将其与 Flutter 示例及其 API 参考文档相结合。如果您在如何映射特定 API 调用方面遇到问题,请针对该特定问题发布一个新问题。
    • 好的弗兰克,谢谢你,我发表在link
    猜你喜欢
    • 2019-05-22
    • 1970-01-01
    • 2019-03-06
    • 2023-03-09
    • 2021-10-27
    • 2020-07-02
    • 2012-02-08
    • 1970-01-01
    • 2017-04-05
    相关资源
    最近更新 更多