【稀饭】react native 实战系列教程之数据存储

来源:互联网 发布:手机淘宝怎么修改店招 编辑:程序博客网 时间:2024/04/29 10:45

概述

在开发一款APP,对于数据的存储是在正常不过了,在此之前,【稀饭】这个应用还没有用到存储数据的地方,为了学习研究React Native的数据存储,打算给应用增加【我的收藏】和【观看历史】这两个功能。接下来,我们来看看如何实现。

我的收藏

关于React Native数据存储的解决方案

关于RN如何存储数据,有两种方案。
- AsyncStorage
- SQLite

第一种是官网提供的一种数据存储方案,它是一个简单的、异步的、持久化的Key-Value文件存储系统,它对于App来说是全局性的。如果你是个android的开发者,那么这就是类似于SharedPreferences,它适用于存储些系统设置、全局变量等简单的key-value数据,不适用于value过于庞大的数据,也不适用于一些包含数据结构等复杂数据;那么针对这种不足,我们需要借助SQLite,轻量的数据库,但RN并没有提供,如果你看完了之前的自定义模块 ,那么你也可以利用原生的SQLiteDatabase开发自己的一个数据库。显然,这种需求很普遍,网上肯定有很多现有的轮子,我们就可以直接拿来用了。这里推荐使用 react-native-sqlite-storage。

实现我的收藏功能

从上面的效果图来看,我们需要在详情页面增加一个收藏按钮,点击之后,空心图变实心图,然后在收藏列表里增加一条数据。要实现这个功能,需要在点击收藏之后,将需要的信息保存到数据库中,然后在列表页读取出来显示。这里利用react-native-sqlite-storage这个第三方库来实现数据的存储。

引入 react-native-sqlite-storage

安装

根据github上的文档说明(Android部分),首先我们在项目根目录下执行cmd命令:

npm install --save react-native-sqlite-storage

如果命令执行很久没有反应,建议换个npm镜像(淘宝镜像)

配置

修改android项目的settings.gradle

// file: android/settings.gradle...include ':react-native-sqlite-storage'project(':react-native-sqlite-storage').projectDir = new File(rootProject.projectDir, '../node_modules/react-native-sqlite-storage/src/android')

修改app\build.gradle

// file: android/app/build.gradle...dependencies {    ...    compile project(':react-native-sqlite-storage')}

修改MainApplication.java,添加SQLitePluginPackage

public class MainApplication extends Application implements ReactApplication {    private final ReactNativeHost mReactNativeHost = new ReactNativeHost(this) {        @Override        protected boolean getUseDeveloperSupport() {            return BuildConfig.DEBUG;        }        @Override        protected List<ReactPackage> getPackages() {            return Arrays.<ReactPackage>asList(                    new MainReactPackage(),                    new OrientationPackage(),                    new VideoViewPackage(),                    new SQLitePluginPackage()            );        }    };    @Override    public ReactNativeHost getReactNativeHost() {        return mReactNativeHost;    }}

到这里算是做好了前期的配置工作,下面结合实际需求讲述如何使用它。

接口封装

首先,我们需要封装一个SQLite模块,方便应用调用。

在项目根目录js下新建db文件夹,然后在js/db/下新建SQLite.js

import React from 'react';import SQLiteStorage from 'react-native-sqlite-storage';SQLiteStorage.DEBUG(true);const SQLite = React.createClass({    render (){        return null;    },});module.exports = SQLite;

该模块类似于工具类,不需要渲染任何界面,所以render return null。

定义打开数据open和关闭数据库close的方法

open(){    db = SQLiteStorage.openDatabase(        database_name,        database_version,        database_displayname,        database_size,        ()=>{            this._successCB('open');        },        (err)=>{            this._errorCB('open',err);        });},close(){    if(db){        this._successCB('close');        db.close();    }else {        console.log("SQLiteStorage not open");    }    db = null;},

创建收藏表

字段 类型 说明 id INTEGER 主键 name VARCHAR 电影名称 actor VARCHAR 主演 time VARCHAR 收藏时间 pic VARCHAR 封面 url VARCHAR 详情地址 title VARCHAR 标题
createTable(){    if (!db) {        open();    }    //创建收藏表    db.transaction((tx)=> {        tx.executeSql('CREATE TABLE IF NOT EXISTS ' + Collection_TABLE_NAME + '(' +            'id INTEGER PRIMARY KEY NOT NULL,' +            'name VARCHAR,' +            'actor VARCHAR,' +            'time VARCHAR,' +            'pic VARCHAR,' +            'url VARCHAR,' +            'title VARCHAR'            + ');'            , [], ()=> {                this._successCB('executeSql');            }, (err)=> {                this._errorCB('executeSql', err);            });    }, (err)=> {        this._errorCB('transaction', err);    }, ()=> {        this._successCB('transaction');    })}

以上完整的代码:

import React from 'react';import SQLiteStorage from 'react-native-sqlite-storage';SQLiteStorage.DEBUG(true);var database_name = "xifan.db";var database_version = "1.0";var database_displayname = "MySQLite";var database_size = -1;var db;const Collection_TABLE_NAME = "Collection";//收藏表const SQLite = React.createClass({    render(){        return null;    },    componentWillUnmount(){        if(db){            this._successCB('close');            db.close();        }else {            console.log("SQLiteStorage not open");        }    },    open(){        db = SQLiteStorage.openDatabase(            database_name,            database_version,            database_displayname,            database_size,            ()=>{                this._successCB('open');            },            (err)=>{                this._errorCB('open',err);            });    },    createTable(){        if (!db) {            open();        }        //创建收藏表        db.transaction((tx)=> {            tx.executeSql('CREATE TABLE IF NOT EXISTS ' + Collection_TABLE_NAME + '(' +                'id INTEGER PRIMARY KEY NOT NULL,' +                'name VARCHAR,' +                'actor VARCHAR,' +                'time VARCHAR,' +                'pic VARCHAR,' +                'url VARCHAR,' +                'title VARCHAR'                + ');'                , [], ()=> {                    this._successCB('executeSql');                }, (err)=> {                    this._errorCB('executeSql', err);                });        }, (err)=> {            this._errorCB('transaction', err);        }, ()=> {            this._successCB('transaction');        })    },    close(){        if(db){            this._successCB('close');            db.close();        }else {            console.log("SQLiteStorage not open");        }        db = null;    },    _successCB(name){        console.log("SQLiteStorage "+name+" success");    },    _errorCB(name, err){        console.log("SQLiteStorage "+name+" error:"+err);    }});module.exports = SQLite;

然后在程序启动进入到首页时去创建表

MainScene.js

import SQLite from './db/SQLite';var sqLite = new SQLite();//省略其它代码componentDidMount(){    sqLite.createTable();}componentWillUnmount(){    sqLite.close();}

启动程序就可以看到成功执行了

create table

以面向对象的思想来说,我们需要为收藏表的字段创建一个实体类对象Movie
在js/db下创建Movie.js

import React from 'react';var id;var name = "";var actor = "";var time = "";var pic = "";var url = "";var title = "";const Movie = React.createClass({    render(){        return null;    }    ,    setId(id){        this.id = id;    },    getId(){        return this.id;    },    setName(name){        this.name = name;    },    getName(){        return this.name;    },    setActor(actor){        this.actor = actor;    },    getActor(){        return this.actor;    },    setTime(time){        this.time = time;    },    getTime(){        return this.time;    },    setPic(pic){        this.pic = pic;    },    getPic(){        return this.pic;    },    setUrl(url){        this.url = url;    },    getUrl(){        return this.url;    },    setTitle(title){        this.title = title;    },    getTitle(){        return this.title;    }});module.exports = Movie;

接着,我们为收藏表增加增删查方法

saveCollection(movie){//保存收藏记录    return new Promise((resolve, reject)=>{        if(db){            db.executeSql(                'INSERT INTO '+Collection_TABLE_NAME+' (name,actor,time,pic,url,title) VALUES(?,?,?,?,?,?)',                [movie.getName(),movie.getActor(),movie.getTime(),movie.getPic(),movie.getUrl(),movie.getTitle()],                ()=>{                    this._successCB('saveCollection');                    resolve();                },                (err)=>{                    this._errorCB('saveCollection',err);                    reject();                })        }else {            reject('db not open');        }    });}
findCollectionByName(name){//通过影片名称获取对应收藏记录    return new Promise((resolve, reject)=>{        if(db){            db.executeSql('SELECT * FROM '+Collection_TABLE_NAME +' WHERE name=? LIMIT 1',[name],                (results)=>{                    console.log(results);                    if(results.rows.length > 0){                        resolve(results.rows.item(0));                    }else {                        reject('not find item');                    }                    this._successCB('findCollectionByName')                },(err)=>{                    reject(err);                    this._errorCB('findCollectionByName',err)                });        }else {            reject('db not open');        }    });}
deleteCollectionByName(name){//通过影片名称删除对应收藏记录    return new Promise((resolve, reject)=>{        if(db){            db.executeSql('DELETE FROM '+Collection_TABLE_NAME +' WHERE name=?',[name],                ()=>{                    resolve();                    this._successCB('deleteCollectionByName');                },(err)=>{                    reject(err);                    this._errorCB('deleteCollectionByName',err);                });        }else {            reject('db not open');        }    });}
listCollection(pageSize,index){//获取收藏记录列表    return new Promise((resolve, reject)=>{        if(db){            db.executeSql('SELECT * FROM '+Collection_TABLE_NAME +' LIMIT '+pageSize+' OFFSET '+((index-1)*pageSize),[],                (results)=>{                    var len = results.rows.length;                    var datas = [];                    for(let i=0;i<len;i++){                        datas.push(results.rows.item(i));                    }                    resolve(datas);                    this._successCB('listCollection');                },(err)=>{                    reject(err);                    this._errorCB('listCollection',err);                });        }else {            reject('db not open');        }    });}

这几个方法都使用到了Promise,这使得对象调用时可以使用链式的方法,更加方便。

接口调用

定义完接口,我们就可以按需求来实现了。在详情页DramaDetailScene.js添加一个收藏按钮,如效果图,这里不在阐述UI的实现,直接来看如何保存数据。

//收藏_onCollectionPress(movie){    console.log(movie);    /*{ name: '信义',        title: '全集中字',        actor: '金喜善,李敏镐,刘德焕,朴世英,李必立,沈恩京,成勋,李民浩',        pic: 'http://img.y3600.com/d/file/p/2016/10/26/40d39df617fc663a21f1e433e67742de.jpg',        url: '/hanju/2016/958.html' }*/    var isCollection = !this.state.isCollection;    if(isCollection){//保存        var coll = new Movie();        coll.setName(movie.name);        coll.setActor(movie.actor);        coll.setPic(movie.pic);        coll.setUrl(movie.url);        coll.setTitle(movie.title);        var date = new Date();        var time=date.getFullYear()+'-'+(date.getMonth()+1)+'-'+date.getDate()+' ';        var hours = date.getHours();        if(hours < 9){            time = time+'0'+hours+':';        }else {            time = time+hours+':';        }        var minutes = date.getMinutes();        if(minutes < 9){            time = time+'0'+minutes+':';        }else {            time = time+minutes+':';        }        var sec = date.getSeconds();        if(sec < 9){            time = time+'0'+sec;        }else {            time = time+sec;        }        coll.setTime(time);        sqlite.saveCollection(coll).then(()=>{            this.setState({                isCollection:isCollection,            });        }).catch((e)=>{}).done();    }else {//删除        sqlite.deleteCollectionByName(this.props.data.name).then(()=>{            this.setState({                isCollection:isCollection,            })        }).catch((e)=>{}).done();    }}

我们通过this.state.isCollection来保存收藏状态。当未收藏时执行保存,已收藏时执行删除。

再者,当我们一进入详情页时,需要知道是否已经收藏。

componentDidMount(){    sqlite.findCollectionByName(this.props.data.name).then((result)=>{        if(result){            this.setState({                isCollection:true,            });        }    }).catch((e)=>{}).done();    this._fetchData(this.props.data.url);}

最后就是在我的收藏列表检索出所有的收藏记录并展示

_queryData(){    sqlite.listCollection(10,index).then((results)=>{        datas = datas.concat(results);        this.setState({            movies:this.state.movies.cloneWithRows(datas),            isRefreshing:false        });    }).catch((err)=>{    }).done();}

【观看历史】也是差不多这个流程,具体的实现不在这里贴代码了,更多请查看我的github

0 0
原创粉丝点击