那么,在Flutter中实现缓存的最简单方法是什么?

15
该应用程序是一个简单的新闻阅读器,显示WordPress文章,没有花哨的东西,不使用BLOC、继承的Widget或Firebase。我希望它能够在用户离线时显示缓存数据(即最新的10篇文章)。
因此,如果用户离线,则显示缓存数据;或者以某种方式将默认数据作为缓存数据。
从WP REST API获取第一篇文章的ID,如果缓存的JSON文件包含Post [id],则显示缓存数据;否则,获取文章并显示加载指示器。还请更新本地JSON文件。
获取JSON数据的代码:
// Function to fetch list of posts
 Future<String> getPosts() async {
 var res = await http
    .get(Uri.encodeFull(apiUrl + "posts?_embed&per_page=10"), //TODO make it unlimited
        headers: {"Accept": "application/json"});

setState(() {
  var resBody = json.decode(res.body);

  posts = resBody;
});

return "Success!";
}

未来获取帖子和节目的载入指示器:

  body: FutureBuilder<List<String>>(
      future: getPosts(),
      builder: (context, snapshot) {
        if (snapshot.hasError) print(snapshot.error);

        return snapshot.hasData
            ? ListViewPosts(posts: snapshot.data)
            : Center(child: CircularProgressIndicator());
      },
    ),

2
LruMap 可能是什么? - pskink
我知道你在问题中说了不要用Firebase,但是你知道它已经提供了这个功能,对吧?你可以获取帖子,将其保存在Firebase数据库中,并且离线使用也将可用。(待续) - Feu
我进行了这个搜索并找到了一些有趣的包。这个看起来正是你想要的,而如果你有大对象,这个可能更适合移动环境。 - Feu
3个回答

22

一个简单的基于时间的缓存不需要太多代码。

这可能会对你有所帮助。它使用了ScopedModel,但它也可以是一个简单的类,只需删除notifyListeners()调用或者替换为自己的机制,如果你想让模型触发UI刷新。

class MyModel extends Model{
    Duration _cacheValidDuration;
    DateTime _lastFetchTime;
    List<MyRecord> _allRecords;



    MyModel(){
        _cacheValidDuration = Duration(minutes: 30);
        _lastFetchTime = DateTime.fromMillisecondsSinceEpoch(0);
        _allRecords = [];
    }



    /// Refreshes all records from the API, replacing the ones that are in the cache.
    /// Notifies listeners if notifyListeners is true.
    Future<void> refreshAllRecords(bool notifyListeners) async{
        _allRecords = await MyApi.getAllRecords(); // This makes the actual HTTP request
        _lastFetchTime = DateTime.now();
        if( notifyListeners ) this.notifyListeners();
    }


    /// If the cache time has expired, or forceRefresh is true, records are refreshed from the API before being returned.
    /// Otherwise the cached records are returned.
    Future<List<MyRecord>> getAllRecords({bool forceRefresh = false}) async{
        bool shouldRefreshFromApi = (null == _allRecords || _allRecords.isEmpty || null == _lastFetchTime || _lastFetchTime.isBefore(DateTime.now().subtract(_cacheValidDuration)) || forceRefresh);

        if( shouldRefreshFromApi )
           await refreshAllRecords(false);

        return _allRecords;
    }
}

要从MyModel获取数据,UI只需要调用getAllRecords()。这将从内存中获取记录(即从_allRecords中)或触发刷新,从而进行HTTP调用并更新记录。缓存的数据会在30分钟后自动过期,如果您想强制刷新(例如,如果用户明确点击刷新按钮),可以传递forceRefresh: true


1
好人,简单回答。 - Du Jianyu

3

在经历了许多缓存解决方案后,以下是我按复杂性排序所学到的:

1- 使用共享偏好设置 2- 使用hive数据库 3- 使用离线服务的firestore 4- 使用sqflite


1 是最复杂的还是最简单的? - who-aditya-nawandar
请问您能否推荐/分享使用Shared Preferences实现此目的的有用链接? - K_Chandio
我非常建议使用HiveDB。 - Hooshyar

0

另一种缓存的方式是使用Hive,一个No-SQL数据库。它可以更快地检索文档并且易于使用。当用户上线时,只需刷新Hive中的数据。

要了解如何使用Hive进行缓存,请查看https://github.com/shashiben/Anime-details获取更多详细信息。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接