第六課:保存和加載數(shù)據(jù)
你知道什么是最煩惱的嗎?如果你創(chuàng)建了一大個待完成的checklist懒构,稍后回來的時候再用的時候,發(fā)現(xiàn)沒有了耘擂。嗯胆剧,這就是應(yīng)用當前的狀態(tài),所以我們將要給用戶提供一個保存用戶數(shù)據(jù)的途徑醉冤。
我們已經(jīng)為他做了一些架構(gòu)準備秩霍,我們訂閱了我們的Observable在每次數(shù)據(jù)變更的時候都調(diào)用了save函數(shù),我們只需要現(xiàn)在來實現(xiàn)這個函數(shù)就可以了蚁阳。
> 修改 src/pages/home/home.ts 里面的 save 方法:
save(): void {
Keyboard.close();
this.dataService.save(this.checklists);
}
如果你不健忘的話铃绒,早些時候我們已經(jīng)生成和導入了一個數(shù)據(jù)服務(wù),所以我們這里只需要調(diào)用他并傳入checklists數(shù)據(jù)螺捐。當然颠悬,我們目前還沒有實現(xiàn)這個數(shù)據(jù)服務(wù),所以他現(xiàn)在不會對數(shù)據(jù)做任何事情定血,我們現(xiàn)在就來彌補他赔癌。注意,我們也調(diào)用了Keyboard的close方法澜沟,由于會在任何數(shù)據(jù)項變更的時候調(diào)用save方法灾票,我們可以用他來在用戶添加或者編輯完數(shù)據(jù)之后確保鍵盤關(guān)閉。
保存數(shù)據(jù)
我們現(xiàn)在要給data.ts碼代碼了茫虽,讓他可以將傳入的任何數(shù)據(jù)保存到存儲里面去刊苍。實際上這個服務(wù)的代碼相當?shù)暮唵危覀儊砜纯矗?br> > 修改 src/providers/data.ts :
import { Storage } from '@ionic/storage';
import { Injectable } from '@angular/core';
@Injectable()
export class Data {
constructor(public storage: Storage){
}
getData(): Promise<any> {
return this.storage.get('checklists');
}
save(data): void {
let saveData = [];
//Remove observables
data.forEach((checklist) => {
saveData.push({
title: checklist.title,
items: checklist.items
});
});
let newData = JSON.stringify(saveData);
this.storage.set('checklists', newData);
}
}
這里有個我們之前沒見過的導入:
import { Storage } from '@ionic/storage';
Storage是Ionic的統(tǒng)一存儲服務(wù)濒析,他負責使用最好的方式來存儲數(shù)據(jù)的同時提供了一個統(tǒng)一的API給供我們使用正什。
當在設(shè)備上運行的時候,如果SQLite插件是可用狀態(tài)的話(我們之前安裝過了)悼枢,他將會使用本地(native)SQLite數(shù)據(jù)庫來存儲數(shù)據(jù)埠忘。由于SQLite數(shù)據(jù)庫只在設(shè)備上可用脾拆,在SQLite不可用的情況下馒索,Storage也會用IndexedDB,WebSQL或者標準瀏覽器的localStorage名船。
盡可能使用SQLite绰上,因為基于瀏覽器的本地存儲不大可靠可以被操作系統(tǒng)默默的清理掉。如果你的數(shù)據(jù)可以被隨機清理掉的話顯然很不理想渠驼。
我們來看看getData函數(shù):
getData(): Promise<any> {
return this.storage.get('checklists');
}
這個函數(shù)允許我們獲取最新的存儲數(shù)據(jù)蜈块,他會以Promise的方式返回數(shù)據(jù)。我們將此函數(shù)的返回的Promise的返回類型設(shè)置為<any>類型,這是一個更復雜的類型百揭。記住爽哎,這不是唯一可用類型,所以器一,如果你覺得很迷惑的話课锌,你可以什么都不加,像這樣:
getData(){
return this.storage.get('checklists');
}
注意祈秕,在這里我們沒有給promise完成的時候添加處理器渺贤,我們只是返回get方法的結(jié)果(一個解析當前存儲數(shù)據(jù)的promise)剑按。記住庆揩,這個行為不是瞬間完成的傅物,這樣我們可以在調(diào)用這個函數(shù)的任何地方添加處理器瘫筐,也更像應(yīng)用的工作流鼠冕。(希望這個能夠更簡單明了)
然后筏养,我們來到了saveData函數(shù)都弹,這個函數(shù)用于將數(shù)據(jù)保存到存儲里:
save(data): void {
let saveData = [];
//Remove observables
data.forEach((checklist) => {
saveData.push({
title: checklist.title,
items: checklist.items
});
});
let newData = JSON.stringify(saveData);
this.storage.set('checklists', newData);
}
之前提到我們仁锯,我們將數(shù)據(jù)存為一個簡單的JSON編碼字符串仙蚜,所以我們調(diào)用了JSON.stringify函數(shù)然后使用set方法將他保存到存儲對象里去玻孟。在做這些之前,我們把數(shù)據(jù)的observable移除掉只加入title和items鳍征,因為他們跟JSON不搭調(diào)(他會引起circular對象錯誤)黍翎,我們后面會重新創(chuàng)建它們。
這就是保存數(shù)據(jù)的全部內(nèi)容艳丛,也沒那么復雜匣掸。我們接下來處理加載數(shù)據(jù)到應(yīng)用中。
加載數(shù)據(jù)
任何時候當用戶打開應(yīng)用氮双,我們都需要從存儲中加載checklists數(shù)據(jù)碰酝,所以最適合做這個操作的地方是home頁的ionViewDidLoad,這個函數(shù)會在頁面加載完成的時候觸發(fā)戴差。我們將對構(gòu)造器進行小小的變更送爸。
> 在 src/pages/home/home.ts 中修改constructor和ionViewDidLoad:
constructor(public nav: NavController, public dataService: Data, public
alertCtrl: AlertController, public platform: Platform) {
}
ionViewDidLoad(){
this.platform.ready().then(() => {
this.dataService.getData().then((checklists) => {
let savedChecklists: any = false;
if(typeof(checklists) != "undefined"){
savedChecklists = JSON.parse(checklists);
}
if(savedChecklists){
savedChecklists.forEach((savedChecklist) => {
let loadChecklist = new ChecklistModel(savedChecklist.title, savedChecklist.items);
this.checklists.push(loadChecklist);
loadChecklist.checklist.subscribe(update => {
this.save();
});
});
}
});
});
}
我們調(diào)用了數(shù)據(jù)服務(wù)里面剛定義的getData函數(shù)。之前也提過暖释,getData函數(shù)返回一個promise而不是直接返回數(shù)據(jù)袭厂,這樣我們可以在加載完成之后處理響應(yīng)。如果getData直接返回數(shù)據(jù)的話球匕,當我們想要訪問他的時候可能他都沒有返回纹磺。
所以我們一直等待取回數(shù)據(jù),然后將checklists傳入到我們的處理器亮曹。首先我們解碼JSON字符串到數(shù)組到這樣我們就可以用來橄杨,然后我們循環(huán)數(shù)組里的每個數(shù)據(jù)項秘症,基于這些數(shù)據(jù)創(chuàng)建一個新的Checklist Data。循環(huán)數(shù)據(jù)和創(chuàng)建新的模型而不是直接將this.checklists設(shè)置為savedChecklists的原因是在保存checklists將他轉(zhuǎn)換成JSON字符串的時候他就喪失了使用數(shù)據(jù)模型里的助理函數(shù)的能力式矫。所以乡摹,我們得利用取得的標題和數(shù)據(jù)項來為所有的checklists創(chuàng)建新的對象。
最后采转,我們重新給Observable設(shè)置監(jiān)聽器趟卸,這樣當數(shù)據(jù)改變的時候就會被處罰。重點關(guān)注我們所作的這些都是在platform.ready()調(diào)用里面進行的氏义,如果在設(shè)備準備好之前這么做的話將會發(fā)生問題锄列。
總結(jié)
這就是本節(jié)課的所有內(nèi)容,數(shù)據(jù)現(xiàn)在在進行任何變更后可以被保存到SQLite數(shù)據(jù)里面去惯悠,應(yīng)用重新打開的時候邻邮,所有數(shù)據(jù)將會重新加載回來。試一下添加一些checklist或者修改checklist的狀態(tài)克婶,然后重新加載應(yīng)用看看對他進行的變更是否還在筒严。