React Native的緩存和下載

一般我們有3種數(shù)據(jù)需要緩存和下載:純文本(比如API返回囤捻,狀態(tài)標(biāo)記等),圖片緩存和其他靜態(tài)文件视哑。

純文本

純文本還是比較簡單的挡毅,RN官方模塊AsyncStorage就夠了跪呈。它就跟HTML5里面的LocalStorage一樣段磨,你可以直接調(diào)setItemgetItem去操作數(shù)據(jù)苹支,這兩個方法都會返回一個promise债蜜。下面是官方的例子:
緩存數(shù)據(jù)

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

獲取數(shù)據(jù)

_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代碼實現(xiàn)的特姐,如果是小數(shù)據(jù)唐含,就存在一個序列化字典里面沫浆,如果數(shù)據(jù)量太大,就單獨存一個文件淮捆。在Android上攀痊,AsyncStorage使用的是RocksDB 或者 SQLite苟径,取決于當(dāng)前設(shè)備支持哪個躬审。需要注意的是,Android上有大小限制遭殉,最大只能存6MB恩沽。這個是RN官方故意的翔始,可以看這里的源碼城瞎。如果需要的話,可以覆蓋這個限制:

  • 找到/android/app/src/main/java/MainApplication.java 并且導(dǎo)入 ReactDatabaseSupplier飒箭。
    import com.facebook.react.modules.storage.ReactDatabaseSupplier;
    
    導(dǎo)入后這個文件看起來像這樣:
    import com.facebook.react.shell.MainReactPackage;
    import com.facebook.soloader.SoLoader;
    import com.facebook.react.modules.storage.ReactDatabaseSupplier;
    
  • 找到 onCreate 并設(shè)置新的 maximumSize弦蹂,我這里設(shè)置為50MB
    long 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變得很大很丑咙崎,如果存儲失敗,雖然會拋錯网杆,但是數(shù)據(jù)并不會回滾碳却,數(shù)據(jù)會更丑追城。如果你需要存儲大的數(shù)據(jù)燥撞,你可以把它存為文件物舒,我們后面會講到

圖片

如果一個圖片我們已經(jīng)加載過一次了冠胯,下次再用的時候我就不想再加載一次了,最好是直接能從緩存讀出來置蜀。官方組件Image 有一個屬性 cache可以支持一些緩存,但是他只支持iOS馋吗。我這里找了兩個比較流行的庫react-native-cached-imagereact-native-fast-image

react-native-cached-image

你可以跟著官方指引來安裝宏粤,我就不多說了绍哎。但是要注意一點崇堰,這個庫依賴 react-native-fetch-blob灿巧。這是一個native模塊抠藕,在執(zhí)行yarn add 或者 npm install后,你需要把它鏈接到你的項目盾似,最簡單的是執(zhí)行react-native link react-native-fetch-blob自動鏈接零院。如果你的項目結(jié)構(gòu)跟自動鏈接的不一樣,你需要手動鏈接告抄,可以參考這里撰茎。
這個庫有三個比較有用的組件,CachedImage, ImageCacheProviderImageCacheManager打洼,這是一個官方例子:

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是用來控制緩存的龄糊,你可以用它下載和刪除圖片,甚至你可以獲取到下載圖片的物理地址募疮。它并沒有緩存優(yōu)先炫惩,強制刷新,強制使用緩存這種預(yù)設(shè)規(guī)則可以用阿浓,具體怎么用需要你自己定義他嚷。

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}
  />

它預(yù)設(shè)了三種模式來控制緩存,其中一個是FastImage.cacheControl.web,這個策略就是網(wǎng)頁是一樣的了,他會采用HTTP的緩存控制頭來控制右莱,前端開發(fā)者應(yīng)該很熟悉胀瞪。這個庫官方有很多例子可以看圆雁,看這里汛蝙。做圖片緩存的話,推薦用這個。

其他靜態(tài)文件

有時候我們需要下載或者緩存一些靜態(tài)文件到設(shè)備上跳昼,比如pdf, mp3, mp4等住拭。rn-fetch-blob是一個可以將你的HTTP返回作為文件存在設(shè)備上的native庫。他其實就是react-native-fetch-blob摊求,但是react-native-fetch-blob沒有繼續(xù)維護(hù)了硫惕,所以就fork過來改了個名字繼續(xù)維護(hù)曼氛。
你只要在請求的配置里面設(shè)置fileCache : true气破,他就會將返回值作為文件存起來,同時返回給你物理路徑,默認(rèn)存的文件是沒有后綴名的佩迟,你可以加參數(shù)設(shè)定后綴,比如: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 ..
  })

在下載和上傳過程中,還可以拿到他的進(jìn)度:

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并不會記錄你的下載歷史,就是說你關(guān)掉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,
    });
  });

檢查是不是已經(jīng)下過這個文件了:

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');
  });
}
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末娩梨,一起剝皮案震驚了整個濱河市狈定,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌措嵌,老刑警劉巖,帶你破解...
    沈念sama閱讀 206,968評論 6 482
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件萌抵,死亡現(xiàn)場離奇詭異揭糕,居然都是意外死亡,警方通過查閱死者的電腦和手機蜀细,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 88,601評論 2 382
  • 文/潘曉璐 我一進(jìn)店門舟铜,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人奠衔,你說我怎么就攤上這事谆刨。” “怎么了涣觉?”我有些...
    開封第一講書人閱讀 153,220評論 0 344
  • 文/不壞的土叔 我叫張陵痴荐,是天一觀的道長。 經(jīng)常有香客問我官册,道長,這世上最難降的妖魔是什么难捌? 我笑而不...
    開封第一講書人閱讀 55,416評論 1 279
  • 正文 為了忘掉前任膝宁,我火速辦了婚禮,結(jié)果婚禮上根吁,老公的妹妹穿的比我還像新娘员淫。我一直安慰自己,他們只是感情好击敌,可當(dāng)我...
    茶點故事閱讀 64,425評論 5 374
  • 文/花漫 我一把揭開白布介返。 她就那樣靜靜地躺著,像睡著了一般沃斤。 火紅的嫁衣襯著肌膚如雪圣蝎。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 49,144評論 1 285
  • 那天衡瓶,我揣著相機與錄音徘公,去河邊找鬼。 笑死哮针,一個胖子當(dāng)著我的面吹牛关面,可吹牛的內(nèi)容都是我干的坦袍。 我是一名探鬼主播,決...
    沈念sama閱讀 38,432評論 3 401
  • 文/蒼蘭香墨 我猛地睜開眼等太,長吁一口氣:“原來是場噩夢啊……” “哼捂齐!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起缩抡,我...
    開封第一講書人閱讀 37,088評論 0 261
  • 序言:老撾萬榮一對情侶失蹤奠宜,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后缝其,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體挎塌,經(jīng)...
    沈念sama閱讀 43,586評論 1 300
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 36,028評論 2 325
  • 正文 我和宋清朗相戀三年内边,在試婚紗的時候發(fā)現(xiàn)自己被綠了榴都。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 38,137評論 1 334
  • 序言:一個原本活蹦亂跳的男人離奇死亡漠其,死狀恐怖嘴高,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情和屎,我是刑警寧澤拴驮,帶...
    沈念sama閱讀 33,783評論 4 324
  • 正文 年R本政府宣布,位于F島的核電站柴信,受9級特大地震影響套啤,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜随常,卻給世界環(huán)境...
    茶點故事閱讀 39,343評論 3 307
  • 文/蒙蒙 一潜沦、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧绪氛,春花似錦唆鸡、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,333評論 0 19
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至序目,卻和暖如春臂痕,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背宛琅。 一陣腳步聲響...
    開封第一講書人閱讀 31,559評論 1 262
  • 我被黑心中介騙來泰國打工刻蟹, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人嘿辟。 一個月前我還...
    沈念sama閱讀 45,595評論 2 355
  • 正文 我出身青樓舆瘪,卻偏偏與公主長得像片效,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子英古,可洞房花燭夜當(dāng)晚...
    茶點故事閱讀 42,901評論 2 345

推薦閱讀更多精彩內(nèi)容

  • 持續(xù)更新中...... 一套企業(yè)級的 UI 設(shè)計語言和 React 實現(xiàn)淀衣。 https://mobile.ant....
    日不落000閱讀 5,660評論 0 35
  • 2018年5月17日上午,太和縣人民法院迎來了民安路小學(xué)的41名小記者和13位班級代表召调,我榮幸成為41名小記...
    yaxin010閱讀 670評論 2 4
  • 一個人的福氣和命運來自這個人的性格。這句話是有道理的艺沼。因為性格決定了內(nèi)心的感覺册舞,和經(jīng)營事物的方式,那么障般,哪些人運氣...
    姑娘頂天立地不怕你閱讀 484評論 0 0
  • 為何调鲸,你眼里 蕩起了一漣憂愁 是昨晚夢里的煩憂 還是路邊那抹青綠的枯榮 為何,這漣憂愁 沉浸我的腦海 遲遲不肯散去...
    中不簡閱讀 207評論 0 1
  • 妙語連珠 迷迷糊糊混日子、大隱隱于市定拟、人列計算機于微、時光飛逝、詭異而深遠(yuǎn)的內(nèi)涵青自、志同道合角雷、遠(yuǎn)征 心靈之約 汪淼繼續(xù)在...
    章魚閱讀 92評論 0 0