React Native的缓存和下载
一般我们有3种数据需要缓存和下载:纯文本(比如API返回,状态标记等),图片缓存和其他静态文件。
纯文本
纯文本还是比较简单的,RN官方模块AsyncStorage就够了。它就跟HTML5里面的LocalStorage一样,你可以直接调setItem和getItem去操作数据,这两个方法都会返回一个promise。下面是官方的例子:
缓存数据
_storeData = async () => {
  try {
    await AsyncStorage.setItem('@MySuperStore:key', 'I like to save it.');
  } catch (error) {
    // Error saving data
  }
};
获取数据
_retrieveData = async () => {
  try {
    const value = await AsyncStorage.getItem('TASKS');
    if (value !== null) {
      // We have data!!
      console.log(value);
    }
  } catch (error) {
    // Error retrieving data
  }
};
在iOS上,AsyncStorage是native代码实现的,如果是小数据,就存在一个序列化字典里面,如果数据量太大,就单独存一个文件。在Android上,AsyncStorage使用的是RocksDB 或者 SQLite,取决于当前设备支持哪个。需要注意的是,Android上有大小限制,最大只能存6MB。这个是RN官方故意的,可以看这里的源码。如果需要的话,可以覆盖这个限制:
- 找到/android/app/src/main/java/MainApplication.java并且导入ReactDatabaseSupplier。import com.facebook.react.modules.storage.ReactDatabaseSupplier;
 导入后这个文件看起来像这样: import com.facebook.react.shell.MainReactPackage;
 import com.facebook.soloader.SoLoader;
 import com.facebook.react.modules.storage.ReactDatabaseSupplier;
 
- 找到 onCreate并设置新的maximumSize,我这里设置为50MBlong size = 50L * 1024L * 1024L; // 50 MB
 ReactDatabaseSupplier.getInstance(getApplicationContext()).setMaximumSize(size);
 改好后的 onCreate看起来是这样:@Override
 public void onCreate() {
 super.onCreate();
 SoLoader.init(this, /* native exopackage */ false); long size = 50L * 1024L * 1024L; // 50 MB
 ReactDatabaseSupplier.getInstance(getApplicationContext()).setMaximumSize(size);
 }
 
虽然可以覆盖这个大小,但是不推荐这么做,这会让DB变得很大很丑,如果存储失败,虽然会抛错,但是数据并不会回滚,数据会更丑。如果你需要存储大的数据,你可以把它存为文件,我们后面会讲到
图片
如果一个图片我们已经加载过一次了,下次再用的时候我就不想再加载一次了,最好是直接能从缓存读出来。官方组件Image 有一个属性 cache可以支持一些缓存,但是他只支持iOS。我这里找了两个比较流行的库react-native-cached-image 和 react-native-fast-image
react-native-cached-image
你可以跟着官方指引来安装,我就不多说了。但是要注意一点,这个库依赖 react-native-fetch-blob。这是一个native模块,在执行yarn add 或者 npm install后,你需要把它链接到你的项目,最简单的是执行react-native link react-native-fetch-blob自动链接。如果你的项目结构跟自动链接的不一样,你需要手动链接,可以参考这里。
这个库有三个比较有用的组件,CachedImage, ImageCacheProvider 和 ImageCacheManager,这是一个官方例子:
import React from 'react';
import {
    CachedImage,
    ImageCacheProvider
} from 'react-native-cached-image';
const images = [
    'https://example.com/images/1.jpg',
    'https://example.com/images/2.jpg',
    'https://example.com/images/3.jpg',
    // ...
];
export default class Example extends React.Component {
    render() {
        return (
            <ImageCacheProvider
                urlsToPreload={images}
                onPreloadComplete={() => console.log('hey there')}>
                <CachedImage source={{uri: images[0]}}/>
                <CachedImage source={{uri: images[1]}}/>
                <CachedImage source={{uri: images[2]}}/>
            </ImageCacheProvider>
        );
    }
}
ImageCacheManager是用来控制缓存的,你可以用它下载和删除图片,甚至你可以获取到下载图片的物理地址。它并没有缓存优先,强制刷新,强制使用缓存这种预设规则可以用,具体怎么用需要你自己定义。
react-native-fast-image
react-native-fast-image用起来更简单一点,在GitHub上的星星也多一点。这是一个native库,在iOS上是包装的 SDWebImage,Android上是包装的Glide (Android),这两个都是原生上万星星的库。因为是native库,所以安装后也需要链接,具体方法跟上面一样。这是一个使用例子:
import FastImage from 'react-native-fast-image'
const YourImage = () =>
  <FastImage
    style={styles.image}
    source={{
      uri: 'https://unsplash.it/400/400?image=1',
      headers:{ Authorization: 'someAuthToken' },
      priority: FastImage.priority.normal,
      cache: FastImage.cacheControl.web
    }}
    resizeMode={FastImage.resizeMode.contain}
  />
它预设了三种模式来控制缓存,其中一个是FastImage.cacheControl.web,这个策略就是网页是一样的了,他会采用HTTP的缓存控制头来控制,前端开发者应该很熟悉。这个库官方有很多例子可以看,看这里。做图片缓存的话,推荐用这个。
其他静态文件
有时候我们需要下载或者缓存一些静态文件到设备上,比如pdf, mp3, mp4等。rn-fetch-blob是一个可以将你的HTTP返回作为文件存在设备上的native库。他其实就是react-native-fetch-blob,但是react-native-fetch-blob没有继续维护了,所以就fork过来改了个名字继续维护。
你只要在请求的配置里面设置fileCache : true,他就会将返回值作为文件存起来,同时返回给你物理路径,默认存的文件是没有后缀名的,你可以加参数设定后缀,比如:appendExt : 'zip'
RNFetchBlob
  .config({
    // add this option that makes response data to be stored as a file,
    // this is much more performant.
    fileCache : true,
    appendExt : 'zip'
  })
  .fetch('GET', 'http://www.example.com/file/example.zip', {
    Authorization : 'Bearer access-token...',
    //some headers ..
  })
  .then((res) => {
    // the temp file path
    console.log('The file saved to ', res.path())
  })
拿到这个路径可以直接用
imageView = <Image source={{ uri : Platform.OS === 'android' ? 'file://' + res.path() : '' + res.path() }}/>
这个库还可以支持文件上传
RNFetchBlob.fetch('POST', 'https://content.dropboxapi.com/2/files/upload', {
    // dropbox upload headers
    Authorization : "Bearer access-token...",
    'Dropbox-API-Arg': JSON.stringify({
      path : '/img-from-react-native.png',
      mode : 'add',
      autorename : true,
      mute : false
    }),
    'Content-Type' : 'application/octet-stream',
    // Change BASE64 encoded data to a file path with prefix `RNFetchBlob-file://`.
    // Or simply wrap the file path with RNFetchBlob.wrap().
  }, RNFetchBlob.wrap(PATH_TO_THE_FILE))
  .then((res) => {
    console.log(res.text())
  })
  .catch((err) => {
    // error handling ..
  })
在下载和上传过程中,还可以拿到他的进度:
RNFetchBlob.fetch('POST', 'http://www.example.com/upload', {
    //... some headers,
    'Content-Type' : 'octet-stream'
  }, base64DataString)
  // listen to upload progress event
  .uploadProgress((written, total) => {
      console.log('uploaded', written / total)
  })
  .then((resp) => {
    // ...
  })
  .catch((err) => {
    // ...
  })
RNFetchBlob
  .config({
    // add this option that makes response data to be stored as a file,
    // this is much more performant.
    fileCache : true,
    appendExt : 'zip'
  })
  .fetch('GET', 'http://www.example.com/file/example.zip', {
    Authorization : 'Bearer access-token...',
    //some headers ..
  })
  // listen to download progress event
  .progress((received, total) => {
      console.log('progress', received / total)
  })
  .then((res) => {
    // the temp file path
    console.log('The file saved to ', res.path())
  })
要注意点的是,rn-fetch-blob并不会记录你的下载历史,就是说你关掉APP再打开,你就不知道你下载的文件哪儿去了。我们可以用AsyncStorage配合着记录下载的历史。
下载完成后记录地址到AsyncStorage:
RNFetchBlob
  .config({
    fileCache: true,
    appendExt: 'pdf',
  })
  .fetch('GET', 'http://pdf.dfcfw.com/pdf/H3_AP201901271289150621_1.pdf')
  .then((response) => {
    const path = response.path();
    this.setState({
      cachedFile: path,
    });
    AsyncStorage.setItem('fileCache', path);
  })
  .catch((error) => {
    this.setState({
      error,
    });
  });
检查是不是已经下过这个文件了:
componentDidMount() {
  AsyncStorage.getItem('fileCache').then((data) => {
    this.setState({
      cachedFile: data,
    });
  });
}
用完了也可以删除这个文件,同时删除记录
clearCache() {
  const { cachedFile } = this.state;
  RNFetchBlob.fs.unlink(cachedFile).then(() => {
    this.setState({
      cachedFile: null,
    });
    AsyncStorage. removeItem('fileCache');
  });
}
React Native的缓存和下载的更多相关文章
- React Native图片缓存解决方案
		1. react-native-fetch-blob 将图片存在本地的一个东西 2. react-native-img-cache 自动缓存的一个东西 上面装好后 就可以使用啦 import {Cac ... 
- React Native清除缓存实现
		清除缓存使用的第三方:react-native-http-cache Github: https://github.com/reactnativecn/react-native-http-cach ... 
- React Native环境配置之Windows版本搭建
		接近年底了,回想这一年都做了啥,学习了啥,然后突然发现,这一年买了不少书,看是看了,就没有完整看完的.悲催. 然后,最近项目也不是很紧了,所以抽空学习了H5.自学啃书还是很无趣的,虽然Head Fir ... 
- React Native官方DEMO
		官方给我们提供了UIExplorer项目,这里边包含React Native的基本所有组件的使用介绍和方法. 运行官方DEMO步骤如下 安装react native环境 React Native项目源 ... 
- react native 入门 (1)- 环境搭建, 创建第一个Hello World
		Create React Native App 是开始构建新的React Native应用程序的最简单方法.它允许您启动项目而无需安装或配置任何工具来构建本机代码 - 无需安装Xcode或Androi ... 
- React Native创建一个APP
		React Native 结合了 Web 应用和 Native 应用的优势,可以使用 JavaScript 来开发 iOS 和 Android 原生应用.在 JavaScript 中用 React 抽 ... 
- React Native for Android  学习
		前言 Facebook 在2015.9.15发布了 React Native for Android,把 JavaScript 开发技术扩展到了移动Android平台.基于React的React Na ... 
- React Native 在用户网络故障时自动调取缓存
		App往往都有缓存功能,例如常见的新闻类应用,如果你关闭网络,你上次打开App加载的数据还在,只是不能加载新的数据了. 我的博客bougieblog.cn,欢迎前来尬聊. 集中处理请求 如果你fetc ... 
- React Native WebView关闭缓存
		React Native WebView关闭缓存 网上搜索没有找到关闭React Native下webview控件的缓存的方法,经测试找到解决方案,记录如下 核心思路:通过请求时设置请求头,使页面缓存 ... 
随机推荐
- LRJ-Example-06-01-Uva210
			#define _CRT_SECURE_NO_WARNINGS #include <cstdio> #include <cstdlib> #include <cstrin ... 
- IntStack(存放int型值,带迭代器) 附模板化实现  p406
			1 该栈只用于存在int型数据 #include "../require.h" #include <iostream> using namespace std; cla ... 
- [转]UEditor编辑器两个版本任意文件上传漏洞分析
			0x01 前言 UEditor是由百度WEB前端研发部开发的所见即所得的开源富文本编辑器,具有轻量.可定制.用户体验优秀等特点 ,被广大WEB应用程序所使用:本次爆出的高危漏洞属于.NET版本,其它的 ... 
- Vue 用第三方的库去实现动画效果
			<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8&quo ... 
- 高可用之keepalived的配置文件详解
			! Configuration File for keepalived global_defs { notification_email { acassen@firewall.loc failover ... 
- BZOJ 2160: 拉拉队排练(回文树)
			传送门: [1]:BZOJ [2]:洛谷 •题意 求串 s 中出现的所有奇回文串,并按照长度由大到小排序: 输出前 k 个奇回文串的乘积 mod 19930726; 如果奇回文串的个数不足 k 个,输 ... 
- java 使用反射调用可变参数方法
			使用反射操作对象-调用可变参数方法 要把可变参数都当做是其对应的数组类型参数; 如 show(XX... is)作为show(XX[] is)调用; 若可变参数元素类型是引用类型: JDK内部接收到参 ... 
- P1072 城市轰炸
			题目描述 一个大小为N*M的城市遭到了X次轰炸,每次都炸了一个每条边都与边界平行的矩形. 在轰炸后,有Y个关键点,指挥官想知道,它们有没有受到过轰炸,如果有,被炸了几次,最后一次是第几轮. 输入格式 ... 
- poll 和 select 底层的数据结构
			poll 和 select 系统调用的真正实现是相当地简单, 对那些感兴趣于它如何工作的人; epoll 更加复杂一点但是建立在同样的机制上. 无论何时用户应用程序调用 poll, select, 或 ... 
- ASP.NET MVC 实现页落网资源分享网站+充值管理+后台管理(11)之支付管理及广告管理
			源码下载地址:http://www.yealuo.com/Sccnn/Detail?KeyValue=c891ffae-7441-4afb-9a75-c5fe000e3d1c 本项目属于个人项目,不支 ... 
