美文网首页
React Native的缓存和下载

React Native的缓存和下载

作者: 海利昂 | 来源:发表于2019-03-04 14:55 被阅读0次

    一般我们有3种数据需要缓存和下载:纯文本(比如API返回,状态标记等),图片缓存和其他静态文件。

    纯文本

    纯文本还是比较简单的,RN官方模块AsyncStorage就够了。它就跟HTML5里面的LocalStorage一样,你可以直接调setItem和getItem去操作数据,这两个方法都会返回一个promise。下面是官方的例子:

    缓存数据

    _storeData =async() => {try{awaitAsyncStorage.setItem('@MySuperStore:key','I like to save it.');  }catch(error) {// Error saving data}};

    获取数据

    _retrieveData =async() => {try{constvalue =awaitAsyncStorage.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。

    importcom.facebook.react.modules.storage.ReactDatabaseSupplier;

    导入后这个文件看起来像这样:

    importcom.facebook.react.shell.MainReactPackage;importcom.facebook.soloader.SoLoader;importcom.facebook.react.modules.storage.ReactDatabaseSupplier;

    找到 onCreate 并设置新的 maximumSize,我这里设置为50MB

    longsize =50L*1024L*1024L;// 50 MB ReactDatabaseSupplier.getInstance(getApplicationContext()).setMaximumSize(size);

    改好后的onCreate看起来是这样:

    @OverridepublicvoidonCreate(){super.onCreate();  SoLoader.init(this,/* native exopackage */false);longsize =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,这是一个官方例子:

    importReactfrom'react';import{    CachedImage,    ImageCacheProvider}from'react-native-cached-image';constimages = ['https://example.com/images/1.jpg','https://example.com/images/2.jpg','https://example.com/images/3.jpg',// ...];exportdefaultclassExampleextendsReact.Component{    render() {return(            console.log('hey there')}>                                                                    );    }}

    ImageCacheManager是用来控制缓存的,你可以用它下载和删除图片,甚至你可以获取到下载图片的物理地址。它并没有缓存优先,强制刷新,强制使用缓存这种预设规则可以用,具体怎么用需要你自己定义。

    react-native-fast-image

    react-native-fast-image用起来更简单一点,在GitHub上的星星也多一点。这是一个native库,在iOS上是包装的 SDWebImage,Android上是包装的Glide (Android),这两个都是原生上万星星的库。因为是native库,所以安装后也需要链接,具体方法跟上面一样。这是一个使用例子:

    importFastImagefrom'react-native-fast-image'constYourImage =()=>

    它预设了三种模式来控制缓存,其中一个是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 pathconsole.log('The file saved to ', res.path())  })

    拿到这个路径可以直接用

    imageView =

    这个库还可以支持文件上传

    RNFetchBlob.fetch('POST','https://content.dropboxapi.com/2/files/upload', {// dropbox upload headersAuthorization :"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 pathconsole.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) =>{constpath = 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的缓存和下载

          本文链接:https://www.haomeiwen.com/subject/tqliuqtx.html